/*
* v m . c
* Forth Inspired Command Language - virtual machine methods
* Author: John Sadler (john_sadler@alum.mit.edu)
* Created: 19 July 1997
* $Id: vm.c,v 1.17 2010/09/13 18:43:04 asau Exp $
*/
/*
* This file implements the virtual machine of Ficl. Each virtual
* machine retains the state of an interpreter. A virtual machine
* owns a pair of stacks for parameters and return addresses, as
* well as a pile of state variables and the two dedicated registers
* of the interpreter.
*/
/*
* Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
* All rights reserved.
*
* Get the latest Ficl release at http://ficl.sourceforge.net
*
* I am interested in hearing from anyone who uses Ficl. If you have
* a problem, a success story, a defect, an enhancement request, or
* if you would like to contribute to the Ficl release, please
* contact me by email at the address above.
*
* L I C E N S E and D I S C L A I M E R
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "ficl.h"
#if FICL_ROBUST >= 2
#else
#endif
/*
* v m B r a n c h R e l a t i v e
*/
void
{
}
/*
* v m C r e a t e
* Creates a virtual machine either from scratch (if vm is NULL on entry)
* or by resizing and reinitializing an existing VM to the specified stack
* sizes.
*/
ficlVm *
{
}
if (vm->returnStack)
#if FICL_WANT_FLOAT
if (vm->floatStack)
#endif
return (vm);
}
/*
* v m D e l e t e
* Free all memory allocated to the specified VM and its subordinate
* structures.
*/
void
{
if (vm) {
#if FICL_WANT_FLOAT
#endif
}
}
/*
* v m E x e c u t e
* Sets up the specified word to be run by the inner interpreter.
* Executes the word's code part immediately, but in the case of
* colon definition, the definition itself needs the inner interpreter
* to complete. This does not happen until control reaches ficlExec
*/
void
{
}
static void
{
switch ((ficlInstruction)(*ip)) {
goto RUNTIME_FIXUP;
ip++;
switch ((ficlInstruction)*destination) {
/* preoptimize where we're jumping to */
destination++;
break;
}
}
}
/*
* v m I n n e r L o o p
* the mysterious inner interpreter...
* This loop is the address interpreter that makes colon definitions
* work. Upon entry, it assumes that the IP points to an entry in
* a definition (the body of a colon word). It runs one word at a time
* until something does vmThrow. The catcher for this is expected to exist
* in the calling code.
* vmThrow gets you out of this loop with a longjmp()
*/
#if FICL_ROBUST <= 1
/* turn off stack checking for primitives */
#else
FICL_PLATFORM_INLINE void
int pushCells)
{
/*
* Why save and restore stack->top?
* So the simple act of stack checking doesn't force a "register" spill,
* which might mask bugs (places where we needed to spill but didn't).
* --lch
*/
}
#endif /* FICL_ROBUST <= 1 */
#if FICL_WANT_FLOAT
#define FLOAT_LOCAL_VARIABLE_SPILL \
#define FLOAT_LOCAL_VARIABLE_REFILL \
#else
#define FLOAT_LOCAL_VARIABLE_SPILL
#define FLOAT_LOCAL_VARIABLE_REFILL
#endif /* FICL_WANT_FLOAT */
#if FICL_WANT_LOCALS
#define LOCALS_LOCAL_VARIABLE_SPILL \
#define LOCALS_LOCAL_VARIABLE_REFILL \
#else
#define LOCALS_LOCAL_VARIABLE_SPILL
#define LOCALS_LOCAL_VARIABLE_REFILL
#endif /* FICL_WANT_FLOAT */
#define LOCAL_VARIABLE_SPILL \
#define LOCAL_VARIABLE_REFILL \
void
{
#if FICL_WANT_FLOAT
ficlFloat f;
#endif /* FICL_WANT_FLOAT */
#if FICL_WANT_LOCALS
#endif /* FICL_WANT_LOCALS */
int except;
int once;
int count;
ficlInteger i;
ficlUnsigned u;
ficlCell c;
char *cp;
if (once)
count = 1;
/* This has to come before the setjmp! */
if (except) {
}
for (;;) {
if (once) {
if (!count--)
break;
} else {
instruction = *ip++;
}
switch (instruction) {
case ficlInstructionInvalid:
"Error: NULL instruction executed!");
return;
case ficlInstruction1:
case ficlInstruction2:
case ficlInstruction3:
case ficlInstruction4:
case ficlInstruction5:
case ficlInstruction6:
case ficlInstruction7:
case ficlInstruction8:
case ficlInstruction9:
case ficlInstruction10:
case ficlInstruction11:
case ficlInstruction12:
case ficlInstruction13:
case ficlInstruction14:
case ficlInstruction15:
case ficlInstruction16:
CHECK_STACK(0, 1);
(++dataTop)->i = instruction;
continue;
case ficlInstruction0:
case ficlInstructionNeg1:
case ficlInstructionNeg2:
case ficlInstructionNeg3:
case ficlInstructionNeg4:
case ficlInstructionNeg5:
case ficlInstructionNeg6:
case ficlInstructionNeg7:
case ficlInstructionNeg8:
case ficlInstructionNeg9:
case ficlInstructionNeg10:
case ficlInstructionNeg11:
case ficlInstructionNeg12:
case ficlInstructionNeg13:
case ficlInstructionNeg14:
case ficlInstructionNeg15:
case ficlInstructionNeg16:
CHECK_STACK(0, 1);
continue;
/*
* stringlit: Fetch the count from the dictionary, then push
* the address and count on the stack. Finally, update ip to
* point to the first aligned address after the string text.
*/
CHECK_STACK(0, 2);
s = (ficlCountedString *)(ip);
continue;
}
CHECK_STACK(0, 1);
s = (ficlCountedString *)(ip);
(++dataTop)->p = s;
continue;
#if FICL_WANT_FLOAT
/* intentional fall-through */
continue;
continue;
continue;
#endif /* FICL_WANT_FLOAT */
/*
* Think of these as little mini-procedures.
* --lch
*/
/* intentional fall-through */
continue;
continue;
continue;
continue;
continue;
#else /* FICL_WANT_SIZE */
#if FICL_WANT_FLOAT
#endif /* FICL_WANT_FLOAT */
#endif /* FICL_WANT_SIZE */
/*
* This is the runtime for (literal). It assumes that it is
* part of a colon definition, and that the next ficlCell
* contains a value to be pushed on the parameter stack at
* runtime. This code is compiled by "literal".
*/
CHECK_STACK(0, 1);
continue;
CHECK_STACK(0, 2);
ip += 2;
continue;
#if FICL_WANT_LOCALS
/*
* Link a frame on the return stack, reserving nCells of space
* for locals - the value of nCells is the next ficlCell in
* the instruction stream.
* 1) Push frame onto returnTop
* 2) frame = returnTop
* 3) returnTop += nCells
*/
case ficlInstructionLinkParen: {
continue;
}
/*
* Unink a stack frame previously created by stackLink
* 1) dataTop = frame
* 2) frame = pop()
*/
continue;
/*
* Immediate - cfa of a local while compiling - when executed,
* compiles code to fetch the value of a local given the
* local's index in the word's pfa
*/
#if FICL_WANT_FLOAT
#endif /* FICL_WANT_FLOAT */
/*
* Immediate - cfa of a local while compiling - when executed,
* compiles code to store the value of a local given the
* local's index in the word's pfa
*/
/*
* Silly little minor optimizations.
* --lch
*/
case ficlInstructionGetLocal0:
case ficlInstructionGetLocal1:
case ficlInstructionToLocal0:
case ficlInstructionToLocal1:
case ficlInstructionTo2Local0:
#endif /* FICL_WANT_LOCALS */
case ficlInstructionPlus:
i = (dataTop--)->i;
dataTop->i += i;
continue;
case ficlInstructionMinus:
i = (dataTop--)->i;
dataTop->i -= i;
continue;
case ficlInstruction1Plus:
dataTop->i++;
continue;
case ficlInstruction1Minus:
dataTop->i--;
continue;
case ficlInstruction2Plus:
dataTop->i += 2;
continue;
case ficlInstruction2Minus:
dataTop->i -= 2;
continue;
case ficlInstructionDup: {
ficlInteger i = dataTop->i;
CHECK_STACK(0, 1);
(++dataTop)->i = i;
continue;
}
if (dataTop->i != 0) {
dataTop++;
}
continue;
case ficlInstructionSwap: {
}
continue;
case ficlInstructionDrop:
CHECK_STACK(1, 0);
dataTop--;
continue;
case ficlInstruction2Drop:
CHECK_STACK(2, 0);
dataTop -= 2;
continue;
case ficlInstruction2Dup:
dataTop += 2;
continue;
case ficlInstructionOver:
dataTop++;
continue;
case ficlInstruction2Over:
dataTop += 2;
continue;
case ficlInstructionPick:
CHECK_STACK(1, 0);
i = dataTop->i;
if (i < 0)
continue;
continue;
/*
* Do stack rot.
* rot ( 1 2 3 -- 2 3 1 )
*/
case ficlInstructionRot:
i = 2;
goto ROLL;
/*
* Do stack roll.
* roll ( n -- )
*/
case ficlInstructionRoll:
CHECK_STACK(1, 0);
i = (dataTop--)->i;
if (i < 1)
continue;
ROLL:
c = dataTop[-i];
i * sizeof (ficlCell));
*dataTop = c;
continue;
/*
* Do stack -rot.
* -rot ( 1 2 3 -- 3 1 2 )
*/
case ficlInstructionMinusRot:
i = 2;
goto MINUSROLL;
/*
* Do stack -roll.
* -roll ( n -- )
*/
case ficlInstructionMinusRoll:
CHECK_STACK(1, 0);
i = (dataTop--)->i;
if (i < 1)
continue;
c = *dataTop;
i * sizeof (ficlCell));
dataTop[-i] = c;
continue;
/*
* Do stack 2swap
* 2swap ( 1 2 3 4 -- 3 4 1 2 )
*/
case ficlInstruction2Swap: {
c = *dataTop;
dataTop[-2] = c;
continue;
}
case ficlInstructionPlusStore: {
CHECK_STACK(2, 0);
continue;
}
case ficlInstructionQuadFetch: {
continue;
}
case ficlInstructionQuadStore: {
CHECK_STACK(2, 0);
continue;
}
case ficlInstructionWFetch: {
continue;
}
case ficlInstructionWStore: {
CHECK_STACK(2, 0);
continue;
}
case ficlInstructionCFetch: {
continue;
}
case ficlInstructionCStore: {
CHECK_STACK(2, 0);
continue;
}
/*
* l o g i c a n d c o m p a r i s o n s
*/
case ficlInstruction0Equals:
continue;
case ficlInstruction0Less:
continue;
case ficlInstruction0Greater:
continue;
case ficlInstructionEquals:
i = (dataTop--)->i;
continue;
case ficlInstructionLess:
i = (dataTop--)->i;
continue;
case ficlInstructionULess:
u = (dataTop--)->u;
continue;
case ficlInstructionAnd:
i = (dataTop--)->i;
continue;
case ficlInstructionOr:
i = (dataTop--)->i;
continue;
case ficlInstructionXor:
i = (dataTop--)->i;
continue;
case ficlInstructionInvert:
continue;
/*
* r e t u r n s t a c k
*/
case ficlInstructionToRStack:
CHECK_STACK(1, 0);
CHECK_RETURN_STACK(0, 1);
continue;
CHECK_STACK(0, 1);
CHECK_RETURN_STACK(1, 0);
continue;
CHECK_STACK(0, 1);
continue;
case ficlInstruction2ToR:
CHECK_STACK(2, 0);
CHECK_RETURN_STACK(0, 2);
dataTop -= 2;
continue;
case ficlInstruction2RFrom:
CHECK_STACK(0, 2);
CHECK_RETURN_STACK(2, 0);
returnTop -= 2;
continue;
case ficlInstruction2RFetch:
CHECK_STACK(0, 2);
continue;
/*
* f i l l
* CORE ( c-addr u char -- )
* If u is greater than zero, store char in each of u
* consecutive characters of memory beginning at c-addr.
*/
case ficlInstructionFill: {
char c;
char *memory;
CHECK_STACK(3, 0);
c = (char)(dataTop--)->i;
u = (dataTop--)->u;
/*
* memset() is faster than the previous hand-rolled
* solution. --lch
*/
continue;
}
/*
* l s h i f t
* l-shift CORE ( x1 u -- x2 )
* Perform a logical left shift of u bit-places on x1,
* giving x2. Put zeroes into the least significant bits
* vacated by the shift. An ambiguous condition exists if
* u is greater than or equal to the number of bits in a
* ficlCell.
*
* r-shift CORE ( x1 u -- x2 )
* Perform a logical right shift of u bit-places on x1,
* giving x2. Put zeroes into the most significant bits
* vacated by the shift. An ambiguous condition exists
* if u is greater than or equal to the number of bits
* in a ficlCell.
*/
case ficlInstructionLShift: {
continue;
}
case ficlInstructionRShift: {
continue;
}
/*
* m a x & m i n
*/
case ficlInstructionMax: {
continue;
}
case ficlInstructionMin: {
continue;
}
/*
* m o v e
* CORE ( addr1 addr2 u -- )
* If u is greater than zero, copy the contents of u
* consecutive address units at addr1 to the u consecutive
* address units at addr2. After MOVE completes, the u
* consecutive address units at addr2 contain exactly
* what the u consecutive address units at addr1 contained
* before the move.
* NOTE! This implementation assumes that a char is the same
* size as an address unit.
*/
case ficlInstructionMove: {
ficlUnsigned u;
char *addr2;
char *addr1;
CHECK_STACK(3, 0);
u = (dataTop--)->u;
if (u == 0)
continue;
/*
* Do the copy carefully, so as to be
* correct even if the two ranges overlap
*/
/* Which ANSI C's memmove() does for you! Yay! --lch */
continue;
}
/*
* s t o d
* s-to-d CORE ( n -- d )
* Convert the number n to the double-ficlCell number d with
* the same numerical value.
*/
case ficlInstructionSToD: {
ficlInteger s;
s = dataTop->i;
/* sign extend to 64 bits.. */
(++dataTop)->i = (s < 0) ? -1 : 0;
continue;
}
/*
* c o m p a r e
* STRING ( c-addr1 u1 c-addr2 u2 -- n )
* Compare the string specified by c-addr1 u1 to the string
* specified by c-addr2 u2. The strings are compared, beginning
* at the given addresses, character by character, up to the
* length of the shorter string or until a difference is found.
* If the two strings are identical, n is zero. If the two
* strings are identical up to the length of the shorter string,
* n is minus-one (-1) if u1 is less than u2 and one (1)
* otherwise. If the two strings are not identical up to the
* length of the shorter string, n is minus-one (-1) if the
* first non-matching character in the string specified by
* c-addr1 u1 has a lesser numeric value than the corresponding
* character in the string specified by c-addr2 u2 and
* one (1) otherwise.
*/
case ficlInstructionCompare:
i = FICL_FALSE;
goto COMPARE;
i = FICL_TRUE;
goto COMPARE;
{
int n = 0;
if (i) {
}
}
if (n == 0)
if (n < 0)
n = -1;
else if (n > 0)
n = 1;
(++dataTop)->i = n;
continue;
}
/*
* r a n d o m
* Ficl-specific
*/
case ficlInstructionRandom:
continue;
/*
* s e e d - r a n d o m
* Ficl-specific
*/
continue;
case ficlInstructionGreaterThan: {
ficlInteger x, y;
y = (dataTop--)->i;
x = dataTop->i;
continue;
}
/*
* This function simply pops the previous instruction
* pointer and returns to the "next" loop. Used for exiting
* from within a definition. Note that exitParen is identical
* to semiParen - they are in two different functions so that
* "see" can correctly identify the end of a colon definition,
* even if it uses "exit".
*/
case ficlInstructionExitParen:
case ficlInstructionSemiParen:
/*
* The first time we run "(branch)", perform a "peephole
* optimization" to see if we're jumping to another
* unconditional jump. If so, just jump directly there.
*/
goto BRANCH_PAREN;
/*
* Same deal with branch0.
*/
/* intentional fall-through */
/*
* Runtime code for "(branch0)"; pop a flag from the stack,
* branch if 0. fall through otherwise.
* The heart of "if" and "until".
*/
CHECK_STACK(1, 0);
if ((dataTop--)->i) {
/*
* don't branch, but skip over branch
* relative address
*/
ip += 1;
continue;
}
/* intentional fall-through! */
/*
* Runtime for "(branch)" -- expects a literal offset in the
* next compilation address, and branches to that location.
*/
BRANCH();
case ficlInstructionOfParen: {
ficlUnsigned a, b;
a = (dataTop--)->u;
b = dataTop->u;
if (a == b) {
/* fall through */
ip++;
/* remove CASE argument */
dataTop--;
} else {
/* take branch to next of or endcase */
BRANCH();
}
continue;
}
case ficlInstructionDoParen: {
CHECK_STACK(2, 0);
/* copy "leave" target addr to stack */
continue;
}
case ficlInstructionQDoParen: {
CHECK_STACK(2, 0);
} else {
ip++;
}
continue;
}
case ficlInstructionLoopParen:
case ficlInstructionPlusLoopParen: {
int direction = 0;
if (instruction == ficlInstructionLoopParen)
index++;
else {
CHECK_STACK(1, 0);
}
/* nuke the loop indices & "leave" addr */
returnTop -= 3;
ip++; /* fall through the loop */
} else { /* update index, branch to loop head */
BRANCH();
}
continue;
}
/*
* Runtime code to break out of a do..loop construct
* Drop the loop control variables; the branch address
* past "loop" is next on the return stack.
*/
case ficlInstructionLeave:
/* almost unloop */
returnTop -= 2;
/* exit */
case ficlInstructionUnloop:
returnTop -= 3;
continue;
case ficlInstructionI:
continue;
case ficlInstructionJ:
continue;
case ficlInstructionK:
continue;
case ficlInstructionDoesParen: {
continue;
}
case ficlInstructionDoDoes: {
CHECK_STACK(0, 1);
continue;
}
#if FICL_WANT_FLOAT
case ficlInstructionF2Fetch:
CHECK_FLOAT_STACK(0, 2);
CHECK_STACK(1, 0);
FLOAT_PUSH_CELL_POINTER_DOUBLE((dataTop--)->p);
case ficlInstructionFFetch:
CHECK_FLOAT_STACK(0, 1);
CHECK_STACK(1, 0);
FLOAT_PUSH_CELL_POINTER((dataTop--)->p);
case ficlInstructionF2Store:
CHECK_FLOAT_STACK(2, 0);
CHECK_STACK(1, 0);
FLOAT_POP_CELL_POINTER_DOUBLE((dataTop--)->p);
case ficlInstructionFStore:
CHECK_FLOAT_STACK(1, 0);
CHECK_STACK(1, 0);
FLOAT_POP_CELL_POINTER((dataTop--)->p);
#endif /* FICL_WANT_FLOAT */
/*
* two-fetch CORE ( a-addr -- x1 x2 )
*
* Fetch the ficlCell pair x1 x2 stored at a-addr.
* x2 is stored at a-addr and x1 at the next consecutive
* ficlCell. It is equivalent to the sequence
* DUP ficlCell+ @ SWAP @ .
*/
case ficlInstruction2Fetch:
PUSH_CELL_POINTER_DOUBLE((dataTop--)->p);
/*
* fetch CORE ( a-addr -- x )
*
* x is the value stored at a-addr.
*/
case ficlInstructionFetch:
PUSH_CELL_POINTER((dataTop--)->p);
/*
* two-store CORE ( x1 x2 a-addr -- )
* Store the ficlCell pair x1 x2 at a-addr, with x2 at a-addr
* and x1 at the next consecutive ficlCell. It is equivalent
* to the sequence SWAP OVER ! ficlCell+ !
*/
case ficlInstruction2Store:
CHECK_STACK(3, 0);
POP_CELL_POINTER_DOUBLE((dataTop--)->p);
/*
* store CORE ( x a-addr -- )
* Store x at a-addr.
*/
case ficlInstructionStore:
CHECK_STACK(2, 0);
POP_CELL_POINTER((dataTop--)->p);
case ficlInstructionComma: {
CHECK_STACK(1, 0);
continue;
}
case ficlInstructionCComma: {
char c;
CHECK_STACK(1, 0);
c = (char)(dataTop--)->i;
continue;
}
case ficlInstructionCells:
continue;
case ficlInstructionCellPlus:
continue;
case ficlInstructionStar:
i = (dataTop--)->i;
dataTop->i *= i;
continue;
case ficlInstructionNegate:
continue;
case ficlInstructionSlash:
i = (dataTop--)->i;
dataTop->i /= i;
continue;
/*
* slash-mod CORE ( n1 n2 -- n3 n4 )
* Divide n1 by n2, giving the single-ficlCell remainder n3
* and the single-ficlCell quotient n4. An ambiguous condition
* exists if n2 is zero. If n1 and n2 differ in sign, the
* implementation-defined result returned will be the
* same as that returned by either the phrase
* NOTE: Ficl complies with the second phrase
* (symmetric division)
*/
case ficlInstructionSlashMod: {
continue;
}
case ficlInstruction2Star:
dataTop->i <<= 1;
continue;
case ficlInstruction2Slash:
dataTop->i >>= 1;
continue;
case ficlInstructionStarSlash: {
ficlInteger x, y, z;
z = (dataTop--)->i;
y = (dataTop--)->i;
x = dataTop->i;
prod = ficl2IntegerMultiply(x, y);
continue;
}
case ficlInstructionStarSlashMod: {
ficlInteger x, y, z;
z = (dataTop--)->i;
y = dataTop[0].i;
x = dataTop[-1].i;
prod = ficl2IntegerMultiply(x, y);
continue;
}
#if FICL_WANT_FLOAT
case ficlInstructionF0:
CHECK_FLOAT_STACK(0, 1);
(++floatTop)->f = 0.0f;
continue;
case ficlInstructionF1:
CHECK_FLOAT_STACK(0, 1);
(++floatTop)->f = 1.0f;
continue;
case ficlInstructionFNeg1:
CHECK_FLOAT_STACK(0, 1);
(++floatTop)->f = -1.0f;
continue;
/*
* Floating point literal execution word.
*/
CHECK_FLOAT_STACK(0, 1);
/*
* Yes, I'm using ->i here,
* but it's really a float. --lch
*/
continue;
/*
* Do float addition r1 + r2.
* f+ ( r1 r2 -- r )
*/
case ficlInstructionFPlus:
f = (floatTop--)->f;
floatTop->f += f;
continue;
/*
* Do float subtraction r1 - r2.
* f- ( r1 r2 -- r )
*/
case ficlInstructionFMinus:
f = (floatTop--)->f;
floatTop->f -= f;
continue;
/*
* Do float multiplication r1 * r2.
* f* ( r1 r2 -- r )
*/
case ficlInstructionFStar:
f = (floatTop--)->f;
floatTop->f *= f;
continue;
/*
* Do float negation.
* fnegate ( r -- r )
*/
case ficlInstructionFNegate:
continue;
/*
* Do float division r1 / r2.
* f/ ( r1 r2 -- r )
*/
case ficlInstructionFSlash:
f = (floatTop--)->f;
floatTop->f /= f;
continue;
/*
* Do float + integer r + n.
* f+i ( r n -- r )
*/
case ficlInstructionFPlusI:
CHECK_STACK(1, 0);
floatTop->f += f;
continue;
/*
* Do float - integer r - n.
* f-i ( r n -- r )
*/
case ficlInstructionFMinusI:
CHECK_STACK(1, 0);
floatTop->f -= f;
continue;
/*
* Do float * integer r * n.
* f*i ( r n -- r )
*/
case ficlInstructionFStarI:
CHECK_STACK(1, 0);
floatTop->f *= f;
continue;
/*
* Do float / integer r / n.
* f/i ( r n -- r )
*/
case ficlInstructionFSlashI:
CHECK_STACK(1, 0);
floatTop->f /= f;
continue;
/*
* Do integer - float n - r.
* i-f ( n r -- r )
*/
case ficlInstructionIMinusF:
CHECK_STACK(1, 0);
continue;
/*
* Do integer / float n / r.
* i/f ( n r -- r )
*/
case ficlInstructionISlashF:
CHECK_STACK(1, 0);
continue;
/*
* Do integer to float conversion.
* int>float ( n -- r )
*/
CHECK_STACK(1, 0);
CHECK_FLOAT_STACK(0, 1);
continue;
/*
* Do float to integer conversion.
* float>int ( r -- n )
*/
CHECK_STACK(0, 1);
CHECK_FLOAT_STACK(1, 0);
continue;
/*
* Add a floating point number to contents of a variable.
* f+! ( r n -- )
*/
case ficlInstructionFPlusStore: {
CHECK_STACK(1, 0);
CHECK_FLOAT_STACK(1, 0);
continue;
}
/*
* Do float stack drop.
* fdrop ( r -- )
*/
case ficlInstructionFDrop:
CHECK_FLOAT_STACK(1, 0);
floatTop--;
continue;
/*
* Do float stack ?dup.
* f?dup ( r -- r )
*/
if (floatTop->f != 0)
goto FDUP;
continue;
/*
* Do float stack dup.
* fdup ( r -- r r )
*/
case ficlInstructionFDup:
FDUP:
floatTop++;
continue;
/*
* Do float stack swap.
* fswap ( r1 r2 -- r2 r1 )
*/
case ficlInstructionFSwap:
c = floatTop[0];
floatTop[-1] = c;
continue;
/*
* Do float stack 2drop.
* f2drop ( r r -- )
*/
case ficlInstructionF2Drop:
CHECK_FLOAT_STACK(2, 0);
floatTop -= 2;
continue;
/*
* Do float stack 2dup.
* f2dup ( r1 r2 -- r1 r2 r1 r2 )
*/
case ficlInstructionF2Dup:
floatTop += 2;
continue;
/*
* Do float stack over.
* fover ( r1 r2 -- r1 r2 r1 )
*/
case ficlInstructionFOver:
floatTop++;
continue;
/*
* Do float stack 2over.
* f2over ( r1 r2 r3 -- r1 r2 r3 r1 r2 )
*/
case ficlInstructionF2Over:
floatTop += 2;
continue;
/*
* Do float stack pick.
* fpick ( n -- r )
*/
case ficlInstructionFPick:
CHECK_STACK(1, 0);
c = *dataTop--;
continue;
/*
* Do float stack rot.
* frot ( r1 r2 r3 -- r2 r3 r1 )
*/
case ficlInstructionFRot:
i = 2;
goto FROLL;
/*
* Do float stack roll.
* froll ( n -- )
*/
case ficlInstructionFRoll:
CHECK_STACK(1, 0);
i = (dataTop--)->i;
if (i < 1)
continue;
c = floatTop[-i];
i * sizeof (ficlCell));
*floatTop = c;
continue;
/*
* Do float stack -rot.
* f-rot ( r1 r2 r3 -- r3 r1 r2 )
*/
case ficlInstructionFMinusRot:
i = 2;
goto FMINUSROLL;
/*
* Do float stack -roll.
* f-roll ( n -- )
*/
CHECK_STACK(1, 0);
i = (dataTop--)->i;
if (i < 1)
continue;
c = *floatTop;
i * sizeof (ficlCell));
floatTop[-i] = c;
continue;
/*
* Do float stack 2swap
* f2swap ( r1 r2 r3 r4 -- r3 r4 r1 r2 )
*/
case ficlInstructionF2Swap: {
c = *floatTop;
floatTop[-2] = c;
continue;
}
/*
* Do float 0= comparison r = 0.0.
* f0= ( r -- T/F )
*/
case ficlInstructionF0Equals:
CHECK_FLOAT_STACK(1, 0);
CHECK_STACK(0, 1);
continue;
/*
* Do float 0< comparison r < 0.0.
* f0< ( r -- T/F )
*/
case ficlInstructionF0Less:
CHECK_FLOAT_STACK(1, 0);
CHECK_STACK(0, 1);
continue;
/*
* Do float 0> comparison r > 0.0.
* f0> ( r -- T/F )
*/
case ficlInstructionF0Greater:
CHECK_FLOAT_STACK(1, 0);
CHECK_STACK(0, 1);
continue;
/*
* Do float = comparison r1 = r2.
* f= ( r1 r2 -- T/F )
*/
case ficlInstructionFEquals:
CHECK_FLOAT_STACK(2, 0);
CHECK_STACK(0, 1);
f = (floatTop--)->f;
continue;
/*
* Do float < comparison r1 < r2.
* f< ( r1 r2 -- T/F )
*/
case ficlInstructionFLess:
CHECK_FLOAT_STACK(2, 0);
CHECK_STACK(0, 1);
f = (floatTop--)->f;
continue;
/*
* Do float > comparison r1 > r2.
* f> ( r1 r2 -- T/F )
*/
case ficlInstructionFGreater:
CHECK_FLOAT_STACK(2, 0);
CHECK_STACK(0, 1);
f = (floatTop--)->f;
continue;
/*
* Move float to param stack (assumes they both fit in a
* single ficlCell) f>s
*/
case ficlInstructionFFrom:
CHECK_FLOAT_STACK(1, 0);
CHECK_STACK(0, 1);
continue;
case ficlInstructionToF:
CHECK_FLOAT_STACK(0, 1);
CHECK_STACK(1, 0);
continue;
#endif /* FICL_WANT_FLOAT */
/*
* c o l o n P a r e n
* This is the code that executes a colon definition. It
* assumes that the virtual machine is running a "next" loop
* (See the vm.c for its implementation of member function
* vmExecute()). The colon code simply copies the address of
* the first word in the list of words to interpret into IP
* after saving its old value. When we return to the "next"
* loop, the virtual machine will call the code for each
* word in turn.
*/
continue;
CHECK_STACK(0, 1);
continue;
CHECK_STACK(0, 1);
continue;
/*
* c o n s t a n t P a r e n
* This is the run-time code for "constant". It simply returns
* the contents of its word's first data ficlCell.
*/
#if FICL_WANT_FLOAT
CHECK_FLOAT_STACK(0, 2);
CHECK_FLOAT_STACK(0, 1);
#endif /* FICL_WANT_FLOAT */
CHECK_STACK(0, 2);
CHECK_STACK(0, 1);
#if FICL_WANT_USER
case ficlInstructionUserParen: {
continue;
}
#endif
default:
/*
* Clever hack, or evil coding? You be the judge.
*
* If the word we've been asked to execute is in fact
* an *instruction*, we grab the instruction, stow it
* in "i" (our local cache of *ip), and *jump* to the
* top of the switch statement. --lch
*/
goto AGAIN;
}
continue;
}
}
}
/*
* v m G e t D i c t
* Returns the address dictionary for this VM's system
*/
{
}
/*
* v m G e t S t r i n g
* Parses a string out of the VM input buffer and copies up to the first
* FICL_COUNTED_STRING_MAX characters to the supplied destination buffer, a
* ficlCountedString. The destination string is NULL terminated.
*
* Returns the address of the first unused character in the dest buffer.
*/
char *
{
if (FICL_STRING_GET_LENGTH(s) > FICL_COUNTED_STRING_MAX) {
}
}
/*
* v m G e t W o r d
* vmGetWord calls vmGetWord0 repeatedly until it gets a string with
* non-zero length.
*/
{
if (FICL_STRING_GET_LENGTH(s) == 0) {
}
return (s);
}
/*
* v m G e t W o r d 0
* Skip leading whitespace and parse a space delimited word from the tib.
* Returns the start address and length of the word. Updates the tib
* to reflect characters consumed, including the trailing delimiter.
* If there's nothing of interest in the tib, returns zero. This function
* does not use vmParseString because it uses isspace() rather than a
* single delimiter character.
*/
{
ficlString s;
char c = 0;
/* Please leave this loop this way; it makes Purify happier. --lch */
for (;;) {
break;
c = *trace;
if (isspace((unsigned char)c))
break;
length++;
trace++;
}
/* skip one trailing delimiter */
trace++;
return (s);
}
/*
* v m G e t W o r d T o P a d
* Does vmGetWord and copies the result to the pad as a NULL terminated
* string. Returns the length of the string. If the string is too long
* to fit in the pad, it is truncated.
*/
int
{
ficlString s;
s = ficlVmGetWord(vm);
if (FICL_STRING_GET_LENGTH(s) > FICL_PAD_SIZE)
return ((int)(FICL_STRING_GET_LENGTH(s)));
}
/*
* v m P a r s e S t r i n g
* Parses a string out of the input buffer using the delimiter
* specified. Skips leading delimiters, marks the start of the string,
* and counts characters to the next delimiter it encounters. It then
* updates the vm input buffer to consume all these chars, including the
* trailing delimiter.
* Returns the address and length of the parsed string, not including the
* trailing delimiter.
*/
{
}
{
ficlString s;
char c;
if (skipLeadingDelimiters) {
trace++;
}
/* find next delimiter or end of line */
for (c = *trace;
c = *++trace) {
;
}
/* set length of result */
/* gobble trailing delimiter */
trace++;
return (s);
}
/*
* v m P o p
*/
{
}
/*
* v m P u s h
*/
void
{
}
/*
* v m P o p I P
*/
void
{
}
/*
* v m P u s h I P
*/
void
{
}
/*
* v m P u s h T i b
* Binds the specified input string to the VM and clears >IN (the index)
*/
void
{
if (pSaveTib) {
}
}
void
{
if (pTib) {
}
}
/*
* v m Q u i t
*/
void
{
}
/*
* v m R e s e t
*/
void
{
ficlVmQuit(vm);
#if FICL_WANT_FLOAT
#endif
}
/*
* v m S e t T e x t O u t
* Binds the specified output callback to the vm. If you pass NULL,
* binds the default output function (ficlTextOut)
*/
void
{
}
void
{
}
void
{
}
/*
* v m T h r o w
*/
void
{
if (vm->exceptionHandler)
}
void
{
}
void
{
/*
* well, we can try anyway, we're certainly not
* returning to our caller!
*/
}
/*
* f i c l E v a l u a t e
* Wrapper for ficlExec() which sets SOURCE-ID to -1.
*/
int
{
int returnValue;
return (returnValue);
}
/*
* f i c l E x e c
* Evaluates a block of input text in the context of the
* specified interpreter. Emits any requested output to the
* interpreter's output function.
*
* Contains the "inner interpreter" code in a tight loop
*
* Returns one of the VM_XXXX codes defined in ficl.h:
* VM_OUTOFTEXT is the normal exit condition
* VM_ERREXIT means that the interpreter encountered a syntax error
* and the vm has been reset to recover (some or all
* of the text block got ignored
* VM_USEREXIT means that the user executed the "bye" command
* to shut down the interpreter. This would be a good
* time to delete the vm, etc -- or you can ignore this
* signal.
*/
int
{
int except;
/*
* Save and restore VM's jmp_buf to enable nested calls to ficlExec
*/
/* This has to come before the setjmp! */
switch (except) {
case 0:
} else { /* set VM up to interpret text */
}
ficlVmInnerLoop(vm, 0);
break;
case FICL_VM_STATUS_RESTART:
break;
#if 0 /* we dont output prompt in loader */
#endif
break;
case FICL_VM_STATUS_USER_EXIT:
case FICL_VM_STATUS_BREAK:
break;
case FICL_VM_STATUS_QUIT:
#if FICL_WANT_LOCALS
#endif
}
ficlVmQuit(vm);
break;
case FICL_VM_STATUS_ABORT:
case FICL_VM_STATUS_ABORTQ:
default: /* user defined exit code?? */
#if FICL_WANT_LOCALS
#endif
}
break;
}
return (except);
}
/*
* f i c l E x e c X T
* Given a pointer to a ficlWord, push an inner interpreter and
* execute the word to completion. This is in contrast with vmExecute,
* which does not guarantee that the word will have completed when
* the function returns (ie in the case of colon definitions, which
* need an inner interpreter to finish)
*
* Returns one of the VM_XXXX exception codes listed in ficl.h. Normal
* exit condition is VM_INNEREXIT, Ficl's private signal to exit the
* inner loop under normal circumstances. If another code is thrown to
* exit the loop, this function will re-throw it if it's nested under
* itself or ficlExec.
*
* NOTE: this function is intended so that C code can execute ficlWords
* given their address in the dictionary (xt).
*/
int
{
int except;
/*
* Save the runningword so that RESTART behaves correctly
* over nested calls.
*/
/*
* Save and restore VM's jmp_buf to enable nested calls
*/
/* This has to come before the setjmp! */
if (except)
else
switch (except) {
case 0:
ficlVmInnerLoop(vm, 0);
break;
case FICL_VM_STATUS_BREAK:
break;
case FICL_VM_STATUS_RESTART:
case FICL_VM_STATUS_USER_EXIT:
case FICL_VM_STATUS_QUIT:
case FICL_VM_STATUS_ABORT:
case FICL_VM_STATUS_ABORTQ:
default: /* user defined exit code?? */
if (oldState) {
}
break;
}
return (except);
}
/*
* f i c l P a r s e N u m b e r
* Attempts to convert the NULL terminated string in the VM's pad to
* a number using the VM's current base. If successful, pushes the number
* onto the param stack and returns FICL_TRUE. Otherwise, returns FICL_FALSE.
* (jws 8/01) Trailing decimal point causes a zero ficlCell to be pushed. (See
* the standard for DOUBLE wordset.
*/
int
{
char isNegative = 0;
char isDouble = 0;
unsigned c;
unsigned digit;
if (length > 1) {
switch (*trace) {
case '-':
trace++;
length--;
isNegative = 1;
break;
case '+':
trace++;
length--;
isNegative = 0;
break;
default:
break;
}
}
/* detect & remove trailing decimal */
isDouble = 1;
length--;
}
if (length == 0) /* detect "+", "-", ".", "+." etc */
return (0); /* false */
if (!isalnum(c))
return (0); /* false */
digit = c - '0';
if (digit > 9)
return (0); /* false */
}
if (isNegative)
if (isDouble) { /* simple (required) DOUBLE support */
if (isNegative)
else
}
return (1); /* true */
}
/*
* d i c t C h e c k
* Checks the dictionary for corruption and throws appropriate
* errors.
* Input: +n number of ADDRESS UNITS (not ficlCells) proposed to allot
* -n number of ADDRESS UNITS proposed to de-allot
* 0 just do a consistency check
*/
void
{
#if FICL_ROBUST >= 1
if ((cells >= 0) &&
}
if ((cells <= 0) &&
}
#else /* FICL_ROBUST >= 1 */
#endif /* FICL_ROBUST >= 1 */
}
void
{
#if FICL_ROBUST >= 1
} else if (dictionary->wordlistCount < 0) {
}
#else /* FICL_ROBUST >= 1 */
#endif /* FICL_ROBUST >= 1 */
}
void
{
}
void
{
}
/*
* f i c l P a r s e W o r d
* From the standard, section 3.4
* b) Search the dictionary name space (see 3.4.2). If a definition name
* matching the string is found:
* 1.if interpreting, perform the interpretation semantics of the definition
* (see 3.4.3.2), and continue at a);
* 2.if compiling, perform the compilation semantics of the definition
* (see 3.4.3.3), and continue at a).
*
* c) If a definition name matching the string is not found, attempt to
* convert the string to a number (see 3.4.1.3). If successful:
* 1.if interpreting, place the number on the data stack, and continue at a);
* 2.if compiling, FICL_VM_STATE_COMPILE code that when executed will place
* the number on the stack (see 6.1.1780 LITERAL), and continue at a);
*
* d) If unsuccessful, an ambiguous condition exists (see 3.4.4).
*
* (jws 4/01) Modified to be a ficlParseStep
*/
int
{
#if FICL_WANT_LOCALS
} else
#endif
if (ficlWordIsCompileOnly(tempFW)) {
"Error: FICL_VM_STATE_COMPILE only!");
}
return (1); /* true */
}
} else { /* (vm->state == FICL_VM_STATE_COMPILE) */
if (ficlWordIsImmediate(tempFW)) {
} else {
ficlCell c;
c.p = tempFW;
else
}
return (1); /* true */
}
}
return (0); /* false */
}