about summary refs log tree commit diff stats
path: root/forth/foreforthfourth/forth-documented.js
diff options
context:
space:
mode:
Diffstat (limited to 'forth/foreforthfourth/forth-documented.js')
-rw-r--r--forth/foreforthfourth/forth-documented.js1076
1 files changed, 1076 insertions, 0 deletions
diff --git a/forth/foreforthfourth/forth-documented.js b/forth/foreforthfourth/forth-documented.js
new file mode 100644
index 0000000..56ccc17
--- /dev/null
+++ b/forth/foreforthfourth/forth-documented.js
@@ -0,0 +1,1076 @@
+// Pure functional approach to Forth interpreter state
+const createInitialState = () => ({
+    stacks: [[], [], [], []],
+    dictionary: new Map(),
+    output: [],
+    compilingWord: null,
+    compilingDefinition: [],
+    stringMode: false,
+    currentString: '',
+    stringPushMode: false,
+    skipMode: false,
+    skipCount: 0,
+    loopStart: null,
+    loopBack: false
+});
+
+// Pure function to update state
+const updateState = (state, updates) => ({
+    ...state,
+    ...updates
+});
+
+// Stack operations
+const pushToStack = (stacks, stackIndex, value) => {
+    const newStacks = stacks.map((stack, i) => 
+        i === stackIndex ? [...stack, value] : stack
+    );
+    return newStacks;
+};
+
+const popFromStack = (stacks, stackIndex) => {
+    const newStacks = stacks.map((stack, i) => 
+        i === stackIndex ? stack.slice(0, -1) : stack
+    );
+    const value = stacks[stackIndex][stacks[stackIndex].length - 1];
+    return { stacks: newStacks, value };
+};
+
+const moveBetweenStacks = (stacks, fromStack, toStack) => {
+    if (stacks[fromStack].length === 0) return { stacks, value: null };
+    const { stacks: newStacks, value } = popFromStack(stacks, fromStack);
+    return { stacks: pushToStack(newStacks, toStack, value), value };
+};
+
+const popAndPrint = (state, stackIndex) => {
+    if (state.stacks[stackIndex].length === 0) {
+        return updateState(state, { output: [...state.output, `Stack ${stackIndex + 1} is empty`] });
+    }
+    const { stacks, value } = popFromStack(state.stacks, stackIndex);
+    return updateState(state, {
+        stacks,
+        output: [...state.output, `Stack ${stackIndex + 1}: ${value}`]
+    });
+};
+
+// Built-in words with documentation
+const builtinWords = {
+    // Stack manipulation for stack 1 (default)
+    'dup': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on dup'] });
+            }
+            const top = state.stacks[0][state.stacks[0].length - 1];
+            return updateState(state, {
+                stacks: pushToStack(state.stacks, 0, top)
+            });
+        },
+        doc: 'Duplicate the top item on the stack',
+        stack: '( x -- x x )'
+    },
+
+    'swap': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on swap'] });
+            }
+            const newStacks = state.stacks.map((stack, i) => [...stack]);
+            const a = newStacks[0].pop();
+            const b = newStacks[0].pop();
+            newStacks[0].push(a);
+            newStacks[0].push(b);
+            return updateState(state, { stacks: newStacks });
+        },
+        doc: 'Exchange the top two items on the stack',
+        stack: '( x1 x2 -- x2 x1 )'
+    },
+
+    'drop': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on drop'] });
+            }
+            const { stacks } = popFromStack(state.stacks, 0);
+            return updateState(state, { stacks });
+        },
+        doc: 'Remove the top item from the stack',
+        stack: '( x -- )'
+    },
+
+    '2drop': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on 2drop'] });
+            }
+            const { stacks: stacks1 } = popFromStack(state.stacks, 0);
+            const { stacks } = popFromStack(stacks1, 0);
+            return updateState(state, { stacks });
+        },
+        doc: 'Remove the top two items from the stack',
+        stack: '( x1 x2 -- )'
+    },
+
+    'over': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on over'] });
+            }
+            const second = state.stacks[0][state.stacks[0].length - 2];
+            return updateState(state, {
+                stacks: pushToStack(state.stacks, 0, second)
+            });
+        },
+        doc: 'Copy the second item on the stack to the top',
+        stack: '( x1 x2 -- x1 x2 x1 )'
+    },
+
+    '2dup': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on 2dup'] });
+            }
+            const top = state.stacks[0][state.stacks[0].length - 1];
+            const second = state.stacks[0][state.stacks[0].length - 2];
+            const newStacks = pushToStack(state.stacks, 0, second);
+            return updateState(state, {
+                stacks: pushToStack(newStacks, 0, top)
+            });
+        },
+        doc: 'Duplicate the top two items on the stack',
+        stack: '( x1 x2 -- x1 x2 x1 x2 )'
+    },
+
+    'rot': {
+        fn: (state) => {
+            if (state.stacks[0].length < 3) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on rot'] });
+            }
+            const newStacks = state.stacks.map((stack, i) => [...stack]);
+            const a = newStacks[0].pop();
+            const b = newStacks[0].pop();
+            const c = newStacks[0].pop();
+            newStacks[0].push(b);
+            newStacks[0].push(a);
+            newStacks[0].push(c);
+            return updateState(state, { stacks: newStacks });
+        },
+        doc: 'Rotate the top three items on the stack',
+        stack: '( x1 x2 x3 -- x2 x3 x1 )'
+    },
+
+    '-rot': {
+        fn: (state) => {
+            if (state.stacks[0].length < 3) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on -rot'] });
+            }
+            const newStacks = state.stacks.map((stack, i) => [...stack]);
+            const a = newStacks[0].pop();
+            const b = newStacks[0].pop();
+            const c = newStacks[0].pop();
+            newStacks[0].push(a);
+            newStacks[0].push(c);
+            newStacks[0].push(b);
+            return updateState(state, { stacks: newStacks });
+        },
+        doc: 'Rotate the top three items on the stack (reverse of rot)',
+        stack: '( x1 x2 x3 -- x3 x1 x2 )'
+    },
+
+    // Arithmetic operations on stack 1
+    '+': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on +'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a + b)
+            });
+        },
+        doc: 'Add the top two numbers on the stack',
+        stack: '( n1 n2 -- n3 )'
+    },
+
+    '-': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on -'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a - b)
+            });
+        },
+        doc: 'Subtract the top number from the second number on the stack',
+        stack: '( n1 n2 -- n3 )'
+    },
+
+    '*': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on *'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a * b)
+            });
+        },
+        doc: 'Multiply the top two numbers on the stack',
+        stack: '( n1 n2 -- n3 )'
+    },
+
+    '/': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on /'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            if (b === 0) {
+                return updateState(state, { 
+                    stacks: pushToStack(pushToStack(stacks2, 0, a), 0, b),
+                    output: [...state.output, 'Error: Division by zero'] 
+                });
+            }
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, Math.floor(a / b))
+            });
+        },
+        doc: 'Divide the second number by the top number on the stack (integer division)',
+        stack: '( n1 n2 -- n3 )'
+    },
+
+    'mod': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on mod'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            if (b === 0) {
+                return updateState(state, { 
+                    stacks: pushToStack(pushToStack(stacks2, 0, a), 0, b),
+                    output: [...state.output, 'Error: Modulo by zero'] 
+                });
+            }
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a % b)
+            });
+        },
+        doc: 'Return the remainder of dividing the second number by the top number',
+        stack: '( n1 n2 -- n3 )'
+    },
+
+    'abs': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on abs'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks, 0, Math.abs(value))
+            });
+        },
+        doc: 'Return the absolute value of the top number on the stack',
+        stack: '( n -- |n| )'
+    },
+
+    'min': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on min'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, Math.min(a, b))
+            });
+        },
+        doc: 'Return the smaller of the top two numbers on the stack',
+        stack: '( n1 n2 -- n3 )'
+    },
+
+    'max': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on max'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, Math.max(a, b))
+            });
+        },
+        doc: 'Return the larger of the top two numbers on the stack',
+        stack: '( n1 n2 -- n3 )'
+    },
+
+    // Comparison and logic
+    '=': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on ='] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a === b ? -1 : 0)
+            });
+        },
+        doc: 'Return true (-1) if the top two numbers are equal, false (0) otherwise',
+        stack: '( n1 n2 -- flag )'
+    },
+
+    '<': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on <'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a < b ? -1 : 0)
+            });
+        },
+        doc: 'Return true (-1) if the second number is less than the top number, false (0) otherwise',
+        stack: '( n1 n2 -- flag )'
+    },
+
+    '>': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on >'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a > b ? -1 : 0)
+            });
+        },
+        doc: 'Return true (-1) if the second number is greater than the top number, false (0) otherwise',
+        stack: '( n1 n2 -- flag )'
+    },
+
+    'and': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on and'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a && b ? -1 : 0)
+            });
+        },
+        doc: 'Return true (-1) if both top two values are true, false (0) otherwise',
+        stack: '( x1 x2 -- flag )'
+    },
+
+    'or': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on or'] });
+            }
+            const { stacks: stacks1, value: b } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: a } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks2, 0, a || b ? -1 : 0)
+            });
+        },
+        doc: 'Return true (-1) if either of the top two values is true, false (0) otherwise',
+        stack: '( x1 x2 -- flag )'
+    },
+
+    'not': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on not'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks, 0, value ? 0 : -1)
+            });
+        },
+        doc: 'Return true (-1) if the top value is false, false (0) if it is true',
+        stack: '( x -- flag )'
+    },
+
+    // Stack inspection
+    '.s': {
+        fn: (state) => {
+            const stackStr = state.stacks[0].length === 0 ? 'empty' : state.stacks[0].join(' ');
+            return updateState(state, {
+                output: [...state.output, `Stack 1 (red): ${stackStr}`]
+            });
+        },
+        doc: 'Display the contents of the red stack (non-destructive)',
+        stack: '( -- )'
+    },
+
+    'depth': {
+        fn: (state) => {
+            return updateState(state, {
+                stacks: pushToStack(state.stacks, 0, state.stacks[0].length)
+            });
+        },
+        doc: 'Push the number of items on the red stack',
+        stack: '( -- n )'
+    },
+
+    '.': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on .'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            return updateState(state, {
+                stacks,
+                output: [...state.output, value.toString()]
+            });
+        },
+        doc: 'Pop and print the top item from the red stack',
+        stack: '( x -- )'
+    },
+
+    // Multi-stack operations
+    'push.red': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on push.red'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks, 0, value)
+            });
+        },
+        doc: 'Move top item from red stack to red stack (no-op, for consistency)',
+        stack: '( x -- x )'
+    },
+
+    'push.teal': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on push.teal'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks, 1, value)
+            });
+        },
+        doc: 'Move top item from red stack to teal stack',
+        stack: '( x -- )'
+    },
+
+    'push.blue': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on push.blue'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks, 2, value)
+            });
+        },
+        doc: 'Move top item from red stack to blue stack',
+        stack: '( x -- )'
+    },
+
+    'push.yellow': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on push.yellow'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            return updateState(state, {
+                stacks: pushToStack(stacks, 3, value)
+            });
+        },
+        doc: 'Move top item from red stack to yellow stack',
+        stack: '( x -- )'
+    },
+
+    'pop.red': {
+        fn: (state) => popAndPrint(state, 0),
+        doc: 'Pop and print top item from red stack',
+        stack: '( x -- )'
+    },
+
+    'pop.teal': {
+        fn: (state) => popAndPrint(state, 1),
+        doc: 'Pop and print top item from teal stack',
+        stack: '( x -- )'
+    },
+
+    'pop.blue': {
+        fn: (state) => popAndPrint(state, 2),
+        doc: 'Pop and print top item from blue stack',
+        stack: '( x -- )'
+    },
+
+    'pop.yellow': {
+        fn: (state) => popAndPrint(state, 3),
+        doc: 'Pop and print top item from yellow stack',
+        stack: '( x -- )'
+    },
+
+    // Utility words
+    'clear': {
+        fn: (state) => updateState(state, {
+            stacks: [[], [], [], []],
+            output: [...state.output, 'All stacks cleared']
+        }),
+        doc: 'Clear all four stacks',
+        stack: '( -- )'
+    },
+
+    // String operations
+    '."': {
+        fn: (state) => {
+            return updateState(state, {
+                stringMode: true,
+                currentString: '',
+                stringPushMode: false
+            });
+        },
+        doc: 'Begin a string literal that will be printed to output',
+        stack: '( -- )'
+    },
+
+    's"': {
+        fn: (state) => {
+            return updateState(state, {
+                stringMode: true,
+                currentString: '',
+                stringPushMode: true
+            });
+        },
+        doc: 'Begin a string literal that will be pushed to the stack',
+        stack: '( -- )'
+    },
+
+    'type': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on type'] });
+            }
+            const { stacks: stacks1, value: length } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: string } = popFromStack(stacks1, 0);
+            return updateState(state, {
+                stacks: stacks2,
+                output: [...state.output, string.toString()]
+            });
+        },
+        doc: 'Print a string from the stack (takes length and string address)',
+        stack: '( addr len -- )'
+    },
+
+    'count': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on count'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            if (typeof value === 'string') {
+                const newStacks = pushToStack(stacks, 0, value.length);
+                return updateState(state, {
+                    stacks: pushToStack(newStacks, 0, value)
+                });
+            } else {
+                const newStacks = pushToStack(stacks, 0, 0);
+                return updateState(state, {
+                    stacks: pushToStack(newStacks, 0, '')
+                });
+            }
+        },
+        doc: 'Extract string info from counted string (returns length and address)',
+        stack: '( c-addr -- c-addr u )'
+    },
+
+    'char+': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on char+'] });
+            }
+            const { stacks: stacks1, value: offset } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: string } = popFromStack(stacks1, 0);
+            if (typeof string === 'string') {
+                return updateState(state, {
+                    stacks: pushToStack(stacks2, 0, string + String.fromCharCode(offset))
+                });
+            } else {
+                return updateState(state, {
+                    stacks: pushToStack(stacks2, 0, string),
+                    output: [...state.output, 'Error: char+ requires string on stack']
+                });
+            }
+        },
+        doc: 'Add a character to a string using ASCII offset',
+        stack: '( c-addr1 char -- c-addr2 )'
+    },
+
+    'strlen': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on strlen'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            if (typeof value === 'string') {
+                return updateState(state, {
+                    stacks: pushToStack(stacks, 0, value.length)
+                });
+            } else {
+                return updateState(state, {
+                    stacks: pushToStack(stacks, 0, 0),
+                    output: [...state.output, 'Error: strlen requires string on stack']
+                });
+            }
+        },
+        doc: 'Get the length of a string on the stack',
+        stack: '( str -- len )'
+    },
+
+    'strcat': {
+        fn: (state) => {
+            if (state.stacks[0].length < 2) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on strcat'] });
+            }
+            const { stacks: stacks1, value: str2 } = popFromStack(state.stacks, 0);
+            const { stacks: stacks2, value: str1 } = popFromStack(stacks1, 0);
+            if (typeof str1 === 'string' && typeof str2 === 'string') {
+                return updateState(state, {
+                    stacks: pushToStack(stacks2, 0, str1 + str2)
+                });
+            } else {
+                return updateState(state, {
+                    stacks: pushToStack(pushToStack(stacks2, 0, str1), 0, str2),
+                    output: [...state.output, `Error: strcat requires two strings, got ${typeof str1} and ${typeof str2}`]
+                });
+            }
+        },
+        doc: 'Concatenate two strings from the stack',
+        stack: '( str1 str2 -- str3 )'
+    },
+
+    // Control flow
+    'if': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on if'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            if (value === 0) {
+                // Skip until THEN or ELSE
+                return updateState(state, {
+                    stacks,
+                    skipMode: true,
+                    skipCount: 0
+                });
+            }
+            return updateState(state, {
+                stacks
+            });
+        },
+        doc: 'Begin conditional execution - if top of stack is false (0), skip to THEN',
+        stack: '( flag -- )'
+    },
+
+    'else': {
+        fn: (state) => {
+            if (state.skipMode) {
+                return updateState(state, {
+                    skipCount: state.skipCount + 1
+                });
+            }
+            // Skip until THEN
+            return updateState(state, {
+                skipMode: true,
+                skipCount: 0
+            });
+        },
+        doc: 'Begin alternative branch in conditional execution',
+        stack: '( -- )'
+    },
+
+    'then': {
+        fn: (state) => {
+            if (state.skipMode && state.skipCount > 0) {
+                return updateState(state, {
+                    skipCount: state.skipCount - 1
+                });
+            } else if (state.skipMode) {
+                return updateState(state, {
+                    skipMode: false,
+                    skipCount: 0
+                });
+            }
+            return state;
+        },
+        doc: 'End conditional execution block',
+        stack: '( -- )'
+    },
+
+    'begin': {
+        fn: (state) => {
+            return updateState(state, {
+                loopStart: state.output.length
+            });
+        },
+        doc: 'Mark the beginning of a loop',
+        stack: '( -- )'
+    },
+
+    'until': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on until'] });
+            }
+            const { stacks, value } = popFromStack(state.stacks, 0);
+            if (value === 0) {
+                // Loop back to BEGIN
+                return updateState(state, {
+                    stacks,
+                    loopBack: true
+                });
+            }
+            return updateState(state, {
+                stacks
+            });
+        },
+        doc: 'End a loop - if top of stack is false (0), loop back to BEGIN',
+        stack: '( flag -- )'
+    },
+
+    // Help and documentation
+    'help': {
+        fn: (state) => {
+            const builtinWordNames = Object.keys(builtinWords);
+            const userWords = Array.from(state.dictionary.keys());
+            const allWords = [...builtinWordNames, ...userWords];
+            
+            const builtinList = builtinWordNames.map(name => {
+                const word = builtinWords[name];
+                return `${name} ${word.stack} - ${word.doc}`;
+            }).join('\n');
+            
+            const userList = userWords.length > 0 ? userWords.join(' ') : 'none';
+            
+            return updateState(state, {
+                output: [
+                    ...state.output,
+                    '=== 4-Stack Forth Interpreter Help ===',
+                    '',
+                    'Built-in words:',
+                    builtinList,
+                    '',
+                    'User defined words: ' + userList,
+                    '',
+                    'Total words: ' + allWords.length,
+                    '',
+                    'Use "doc <word>" to get detailed help for a specific word',
+                    'Use "words" to see just the word names'
+                ]
+            });
+        },
+        doc: 'Display comprehensive help information for all available words',
+        stack: '( -- )'
+    },
+
+    'doc': {
+        fn: (state) => {
+            if (state.stacks[0].length === 0) {
+                return updateState(state, { output: [...state.output, 'Error: Stack underflow on doc'] });
+            }
+            const { stacks, value: wordName } = popFromStack(state.stacks, 0);
+            
+            // Check built-in words first
+            if (builtinWords[wordName]) {
+                const word = builtinWords[wordName];
+                return updateState(state, {
+                    stacks,
+                    output: [
+                        ...state.output,
+                        `=== ${wordName} ===`,
+                        `Stack effect: ${word.stack}`,
+                        `Description: ${word.doc}`,
+                        `Type: Built-in word`
+                    ]
+                });
+            }
+            
+            // Check user-defined words
+            if (state.dictionary.has(wordName)) {
+                const definition = state.dictionary.get(wordName);
+                return updateState(state, {
+                    stacks,
+                    output: [
+                        ...state.output,
+                        `=== ${wordName} ===`,
+                        `Definition: ${definition.join(' ')}`,
+                        `Type: User-defined word`
+                    ]
+                });
+            }
+            
+            return updateState(state, {
+                stacks,
+                output: [...state.output, `Word '${wordName}' not found`]
+            });
+        },
+        doc: 'Display documentation for a specific word',
+        stack: '( "word" -- )'
+    },
+
+    'words': {
+        fn: (state) => {
+            const builtinWordNames = Object.keys(builtinWords);
+            const userWords = Array.from(state.dictionary.keys());
+            const allWords = [...builtinWordNames, ...userWords];
+            
+            const builtinList = builtinWordNames.join(' ');
+            const userList = userWords.length > 0 ? userWords.join(' ') : 'none';
+            
+            return updateState(state, {
+                output: [
+                    ...state.output,
+                    'Built-in words: ' + builtinList,
+                    'User defined words: ' + userList,
+                    'Total words: ' + allWords.length
+                ]
+            });
+        },
+        doc: 'List all available words (built-in and user-defined)',
+        stack: '( -- )'
+    }
+};
+
+// Parse and execute Forth input
+const parseAndExecute = (state, input) => {
+    const tokens = input.trim().split(/\s+/).filter(token => token.length > 0);
+    return tokens.reduce(executeToken, state);
+};
+
+// Execute a single token
+const executeToken = (state, token) => {
+    // Handle string mode
+    if (state.stringMode) {
+        // Check if this token contains the closing quote
+        const quoteIndex = token.indexOf('"');
+        if (quoteIndex !== -1) {
+            // Token contains closing quote
+            const beforeQuote = token.substring(0, quoteIndex);
+            const afterQuote = token.substring(quoteIndex + 1);
+            
+            // Add the part before the quote to the string
+            const finalString = state.currentString + (state.currentString ? ' ' : '') + beforeQuote;
+            
+            // End string mode and handle based on mode
+            let newState;
+            if (state.stringPushMode) {
+                // Push mode: add string to stack
+                newState = updateState(state, {
+                    stringMode: false,
+                    currentString: '',
+                    stringPushMode: false,
+                    stacks: pushToStack(state.stacks, 0, finalString)
+                });
+            } else {
+                // Print mode: add to output
+                newState = updateState(state, {
+                    stringMode: false,
+                    currentString: '',
+                    stringPushMode: false,
+                    output: [...state.output, finalString]
+                });
+            }
+            
+            // If there's content after the quote, process it
+            if (afterQuote.trim()) {
+                newState = ForthInterpreter.parseAndExecute(newState, afterQuote);
+            }
+            
+            return newState;
+        } else {
+            // Add to current string
+            return updateState(state, {
+                currentString: state.currentString + (state.currentString ? ' ' : '') + token
+            });
+        }
+    }
+
+    // Handle skip mode (for control flow)
+    if (state.skipMode) {
+        if (token === 'if' || token === 'begin') {
+            return updateState(state, {
+                skipCount: state.skipCount + 1
+            });
+        } else if (token === 'then' || token === 'until') {
+            if (state.skipCount > 0) {
+                return updateState(state, {
+                    skipCount: state.skipCount - 1
+                });
+            } else {
+                return updateState(state, {
+                    skipMode: false,
+                    skipCount: 0
+                });
+            }
+        } else if (token === 'else') {
+            if (state.skipCount === 0) {
+                // Switch to skipping ELSE branch
+                return updateState(state, {
+                    skipMode: true,
+                    skipCount: 0
+                });
+            }
+        }
+        // Skip this token
+        return state;
+    }
+
+    // Handle move operation state machine
+    if (state.moveInProgress) {
+        if (state.moveFromStack === null) {
+            // Expecting source stack number
+            const from = parseInt(token);
+            if (isNaN(from) || from < 1 || from > 4) {
+                return updateState(state, {
+                    moveInProgress: false,
+                    moveFromStack: null,
+                    output: [...state.output, 'Error: Invalid source stack. Must be 1-4']
+                });
+            }
+            if (state.stacks[from - 1].length === 0) {
+                return updateState(state, {
+                    moveInProgress: false,
+                    moveFromStack: null,
+                    output: [...state.output, `Error: Stack ${from} is empty`]
+                });
+            }
+            return updateState(state, {
+                moveInProgress: true,
+                moveFromStack: from - 1, // Convert to 0-based index
+                output: [...state.output, `Moving from stack ${from}. Enter destination stack (1-4):`]
+            });
+        } else {
+            // Expecting destination stack number
+            const to = parseInt(token);
+            if (isNaN(to) || to < 1 || to > 4) {
+                return updateState(state, {
+                    moveInProgress: false,
+                    moveFromStack: null,
+                    output: [...state.output, 'Error: Invalid destination stack. Must be 1-4']
+                });
+            }
+            const toIndex = to - 1; // Convert to 0-based index
+            const fromIndex = state.moveFromStack;
+            
+            // Reset move state
+            const newState = updateState(state, {
+                moveInProgress: false,
+                moveFromStack: null
+            });
+            
+            // Perform the move
+            const { stacks, value } = popFromStack(newState.stacks, fromIndex);
+            return updateState(newState, {
+                stacks: pushToStack(stacks, toIndex, value),
+                output: [...newState.output, `Moved ${value} from stack ${fromIndex + 1} to stack ${toIndex + 1}`]
+            });
+        }
+    }
+
+    // Handle word definition compilation
+    if (state.compilingWord !== null) {
+        if (token === ';') {
+            const newDictionary = new Map(state.dictionary);
+            newDictionary.set(state.compilingWord, [...state.compilingDefinition]);
+            return updateState(state, {
+                dictionary: newDictionary,
+                compilingWord: null,
+                compilingDefinition: [],
+                output: [...state.output, `Word '${state.compilingWord}' defined`]
+            });
+        }
+        
+        // If we're expecting a name, capture it
+        if (state.compilingWord === 'EXPECTING_NAME') {
+            return updateState(state, {
+                compilingWord: token,
+                compilingDefinition: []
+            });
+        }
+        
+        // Otherwise, add to definition
+        return updateState(state, {
+            compilingDefinition: [...state.compilingDefinition, token]
+        });
+    }
+
+    // Handle word definition start
+    if (token === ':') {
+        return updateState(state, {
+            compilingWord: 'EXPECTING_NAME',
+            compilingDefinition: []
+        });
+    }
+
+    // Check if it's a built-in word
+    if (builtinWords[token]) {
+        return builtinWords[token].fn(state);
+    }
+
+    // Check if it's a user-defined word
+    if (state.dictionary.has(token)) {
+        const definition = state.dictionary.get(token);
+        return definition.reduce(executeToken, state);
+    }
+
+    // Check if it's a number
+    const num = parseFloat(token);
+    if (!isNaN(num)) {
+        return updateState(state, {
+            stacks: pushToStack(state.stacks, 0, num)
+        });
+    }
+
+    // Check if it's a move command
+    if (token === 'move') {
+        return updateState(state, {
+            moveInProgress: true,
+            moveFromStack: null
+        });
+    }
+
+    // Unknown token
+    return updateState(state, {
+        output: [...state.output, `Error: Unknown word '${token}'`]
+    });
+};
+
+// Export for use in other modules or testing
+if (typeof module !== 'undefined' && module.exports) {
+    module.exports = {
+        createInitialState,
+        parseAndExecute,
+        executeToken,
+        builtinWords,
+        updateState,
+        pushToStack,
+        popFromStack
+    };
+} else if (typeof window !== 'undefined') {
+    // Browser environment
+    window.ForthInterpreter = {
+        createInitialState,
+        parseAndExecute,
+        executeToken,
+        builtinWords,
+        updateState,
+        pushToStack,
+        popFromStack
+    };
+}