<!-- ********************************************************************************** -->
<!-- Copywrite 2008 K. Jacobson solidcoding.blogspot.com                                -->
<!-- wForth.js                                                                          -->
<!--                                                                                    -->
<!-- 12/3/2008                                                                           -->
<!--                                                                                    -->
<!-- ********************************************************************************** -->

     function StringBuilder() {
         this.buffer = [];
         this.append = function(line) {
             this.buffer.push(line);
         }
         this.appendLine = function(line) {
             this.buffer.push(line + "\n");
         }
         this.toString = function() {
             return this.buffer.join("");
         }
     }
     
    String.prototype.startsWith = function(value) {
        if (this.length < value.length) {
            return false;
        }
        var org = this.substring(0, value.length);
        return org == value;
    }
    
    String.prototype.fixQuotes = function() {
        var builder = new StringBuilder();
        var count = 0;
        for(count = 0; count < this.length;count++) {
            if(this.charCodeAt(count) == 8221 /* ” */) {
                builder.append('"');
            }
            else {
                builder.append(this.charAt(count));
            }
        }
        return builder.toString();
    }

    function Match(isSuccess, val) {
        this.Success = isSuccess;
        this.Value = val;
    }

    function Regex(strpattern) {
        this.pattern = strpattern;
        this.match = function(input) {
            if (this.pattern == "") {
                return new Match(false, null);
            }
            var rg = new RegExp(this.pattern);
            var result = rg.exec(input);
            if (result == null) {
                return new Match(false, null);
            }
            return new Match(true, result[0]);
        }

        this.matches = function(input) {
            var lst = [];
            if (this.pattern == "") {
                return lst;
            }
            var temp = input;
            var rg = new RegExp(this.pattern);
            var result = rg.exec(temp);

            while (result != null) {
                lst.push(result[0]);
                var pos = temp.indexOf(result) + result[0].length;
               	temp = temp.substring(pos);
                result = rg.exec(temp);
            }
            return lst;
        }
    }

    function ForthParser() {
        this.pattern = "\\.\"[^\"]*\"|\"[^\"]*\"|\\S+";
       

        this.getIntructions = function(strLines) {
            var temp = strLines.fixQuotes();
            var lines = temp.split('\n');
            var count = 0;
	        var instructList = new Array();
	        var reg = new Regex(this.pattern);
            for (count = 0; count < lines.length; count++) {
		        var  temp = reg.matches(lines[count]);
		        if (temp!= null) {
		            //instructList = instructList.concat(temp);
		            var count2 = 0;
		            
		            var comments = false;
		            for(count2 = 0; count2 < temp.length; count2++) {
		                var prospect = temp[count2];
		                if (prospect.startsWith("\\")) {
		                    //full comment line. Move on to next line
		                    count2 = temp.length;
		                }
		                else {
		                    if (prospect.startsWith("(")) {
		                        //start inline comments
		                        comments = true;
		                    }
		                    if (prospect.lastIndexOf(')') == prospect.length -1) {
		                        //end inline comments
		                        comments = false;
		                        continue;
		                    }
		                    if (comments == false) {
		                        instructList.push(prospect);
		                    }
		                }
		            }
		        }
            }
            return instructList;
        }
    }

    function SystemWord(name, jsCode) {
        this.name = name;
        this.jsCode = jsCode;
    }

    function SystemDictionary() {
        this.list = new Array();
        this.list.push(new SystemWord("drop", "Forth.drop();"));
        this.list.push(new SystemWord("swap", "Forth.swap();"));
        this.list.push(new SystemWord(":", "Forth.call();"));
        this.list.push(new SystemWord("rot", "Forth.rot();"));
        this.list.push(new SystemWord("dup", "Forth.dup();"));
        this.list.push(new SystemWord("-dup", "Forth.dashDup();"));
        this.list.push(new SystemWord("over", "Forth.over();"));
        this.list.push(new SystemWord("true", "Forth.True();"));
        this.list.push(new SystemWord("false", "Forth.False();"));
        this.list.push(new SystemWord(";", "Forth.end();"));
        this.list.push(new SystemWord(".", "Forth.dotget();"));
        this.list.push(new SystemWord("cr", "Forth.cr();"));
        this.list.push(new SystemWord("space", "Forth.space();"));
        this.list.push(new SystemWord("spaces", "Forth.spaces();"));
        this.list.push(new SystemWord("emit", "Forth.emit();"));
        this.list.push(new SystemWord("+", "Forth.add();"));
        this.list.push(new SystemWord("-", "Forth.subtract();"));
        this.list.push(new SystemWord("/", "Forth.divide();"));
        this.list.push(new SystemWord("*", "Forth.multiply();"));
        this.list.push(new SystemWord("mod", "Forth.mod();"));
        this.list.push(new SystemWord("/mod", "Forth.slashMod();"));
        this.list.push(new SystemWord("*/", "Forth.starSlash();"));
        this.list.push(new SystemWord("abs", "Forth.abs();"));
        this.list.push(new SystemWord("min", "Forth.min();"));
        this.list.push(new SystemWord("max", "Forth.max();"));
        this.list.push(new SystemWord("if", "Forth.If();"));
        this.list.push(new SystemWord("else", "Forth.Else();"));
        this.list.push(new SystemWord("then", "Forth.Then();"));
        this.list.push(new SystemWord(">r", "Forth.tor();"));
        this.list.push(new SystemWord("i", "Forth.I();"));
        this.list.push(new SystemWord("do", "Forth.Do();"));
        this.list.push(new SystemWord("loop", "Forth.Loop();"));
        this.list.push(new SystemWord("+loop", "Forth.PlusLoop();"));

        this.list.push(new SystemWord("1+", "Forth.onePlus();"));
        this.list.push(new SystemWord("1-", "Forth.oneMinus();"));
        this.list.push(new SystemWord("2+", "Forth.twoPlus();"));
        this.list.push(new SystemWord("2-", "Forth.twoMinus();"));
        this.list.push(new SystemWord("2*", "Forth.twoMultiply();"));
        this.list.push(new SystemWord("2/", "Forth.twoDivide();"));
        this.list.push(new SystemWord("0=", "Forth.zeroEqual();"));
        this.list.push(new SystemWord("0<", "Forth.zeroLess();"));
        this.list.push(new SystemWord("0>", "Forth.zeroGreater();"));
        this.list.push(new SystemWord("<", "Forth.lessThan();"));
        this.list.push(new SystemWord(">", "Forth.greaterThan();"));
        this.list.push(new SystemWord("<=", "Forth.lessThanOrEqual();"));
        this.list.push(new SystemWord(">=", "Forth.greaterThanOrEqual();"));
        this.list.push(new SystemWord("=", "Forth.equal();"));
        this.list.push(new SystemWord("<>", "Forth.notEqual();"));
        this.list.push(new SystemWord("~and", "Forth.bitwiseAnd();"));
        this.list.push(new SystemWord("~xor", "Forth.bitwiseXor);"));
        this.list.push(new SystemWord("~not", "Forth.bitwiseNot();"));
        this.list.push(new SystemWord("and", "Forth.logicalAnd();"));
        this.list.push(new SystemWord("or", "Forth.logicalOr();"));
        this.list.push(new SystemWord("not", "Forth.logicalNot();"));
        this.list.push(new SystemWord("quit", "Forth.quit();"));
        this.list.push(new SystemWord("leave", "Forth.leave();"));
        this.list.push(new SystemWord("begin", "Forth.begin();"));
        this.list.push(new SystemWord("until", "Forth.until();"));
        this.list.push(new SystemWord("while", "Forth.While();"));
        this.list.push(new SystemWord("repeat", "Forth.repeat();"));
        this.list.push(new SystemWord("bye", "Forth.bye();"));
        this.list.push(new SystemWord("forget", "Forth.forget();"));
        this.list.push(new SystemWord("pace", "Forth.pace();"));
        this.getWord = function(name) {
            for (count = 0; count < this.list.length; count++) {
                var test = this.list[count].name;
                if (test == name.toLowerCase()) {
                    return this.list[count];
                }
            }
            return null;
        }
    }

    function ForthMachine() {
        this.memoryStack = new Array();
        this.sp = 0;
        this.spOrgin = 0;
        this.tibPointer = 0;
        this.tibStart = 0;
        this.rsp = 0;
        this.rspOrgin = 0;

        this.executionStack = new Array();
        this.codePointer = 0;

        this.loopStack = new Array();

        this.console = null;
        
        this.consoleLastIndex = 0;
        
        this.interrupt = 0;

        //pointer to the user dictionary
        this.latest = null;
        //system dict
        this.systemDic = new SystemDictionary();

        //set memory sizes
        var padSize = 64;
        var tibSize = 80;
        var stackSize = 1024;
        var returnStackSize = 1024;

        //initialize memory block
        var count = 0;
        for (count = 0; count < padSize + tibSize + stackSize + returnStackSize; count++) {
            this.memoryStack.push(0);
        }

        //set pointers
        this.tibStart = padSize + 1;
        this.spOrgin = this.tibPointer + tibSize + 1;
        this.rspOrgin = this.spOrgin + stackSize + 1;

        this.sp = this.spOrgin;
        this.rsp = this.rspOrgin;
        this.tibPointer = this.tibStart;

        this.endOfProgram = function() {
            return this.codePointer == this.executionStack.length;
        }

        this.getInterpretValue = function() {
            if (this.endOfProgram()) {
                return null;
            }
            return this.executionStack[this.codePointer++];
        }

        this.searchUserDict = function(name) {
            if (this.latest == null) {
                return null;
            }
            var word = this.latest;
            do {
                if (word.name == name) {
                    return word;
                }
                word = word.next;
            } while (word != null);
        }

        this.stackUnderFlowException = function() {
            throw new Error("Stack empty");
        }

        this.stackFullException = function() {
            throw new Error("Stack full");
        }

        this.pop = function() {
            if (!(this.sp > this.spOrgin)) {
                this.stackUnderFlowException();
            }
            return this.memoryStack[this.sp--];
        }

        this.push = function(value) {
            if (this.sp >= this.rspOrgin) {
                this.stackFullException();
            }
            this.memoryStack[++this.sp] = value;
        }

        this.peek = function() {
            if (this.sp == this.spOrgin) {
                this.stackUnderFlowException();
            }
            return this.memoryStack[this.sp];
        }

        this.rpop = function() {
            if (!(this.rsp > this.rspOrgin)) {
                this.stackUnderFlowException();
            }
            return this.memoryStack[this.rsp--];
        }

        this.rpush = function(value) {
            if (this.rsp >= this.memoryStack.length) {
                this.stackFullException();
            }
            this.memoryStack[++this.rsp] = value;
        }

        this.rpeek = function() {
            if (this.rsp == this.rspOrgin) {
                this.stackUnderFlowException();
            }
            return this.memoryStack[this.rsp];
        }

        this.addToDict = function(word) {
            word.next = this.latest;
            this.latest = word;
        }

        this.write = function(str) {
            if (this.console == null) {
                return;
            }
            var temp = this.console.value;
            temp = temp + str;
            temp = temp.slice(-600);
            this.console.value = temp;
            this.consoleLastIndex = this.console.value.length;
            this.console.scrollTop = this.console.scrollHeight;
        }

        this.getLoopIndex = function() {
            if (this.loopStack.length == 0) {
                return null;
            }
            return this.loopStack[this.loopStack.length - 1];
        }
    }

    function ForthWord() {
        this.name = "";
        this.code = "";
        this.next = "";
    }

    var engine = new ForthMachine();

    //forth keywords
    if (!this.Forth) {
        Forth = function() {

            function execute(sysWord) {
                var code = sysWord.jsCode;
                eval(code);
            }

            function addSub(userWord) {
                //store the current position
                engine.rpush(engine.codePointer);
                //store the beginning of sub
                engine.rpush(engine.executionStack.length);
                //move code pointer to beginner of sub
                engine.codePointer = engine.executionStack.length;
                //add code array to end of execution stack
                engine.executionStack = engine.executionStack.concat(userWord.code);
            }

            function endSub() {
                if (engine.rsp == engine.rspOrgin) {
                    return;
                }
                var subStart = engine.rpop();
                engine.codePointer = engine.rpop();
                engine.executionStack = engine.executionStack.slice(0, subStart);
            }
            

            return {
                //stack manipulation
                drop: function(arg) {
                    engine.pop(arg);
                },
                swap: function() {
                    var top = engine.pop();
                    var sec = engine.pop();
                    engine.push(top);
                    engine.push(sec);
                },
                rot: function() {
                    var top = engine.pop();
                    var sec = engine.pop();
                    var thrd = engine.pop();
                    engine.push(sec);
                    engine.push(thrd);
                    engine.push(top);
                },
                dup: function() {
                    engine.push(engine.peek());
                },
                dashDup: function() {
                    if (engine.peek() != 0) {
                        engine.push(engine.peek());
                    }
                },
                over: function() {
                    var top = engine.pop();
                    var sec = engine.peek();
                    engine.push(top);
                    engine.push(sec);
                },

                lit: function(arg) {
                    engine.push(arg);
                },

                True: function() {
                    engine.push(1);
                },

                False: function() {
                    engine.push(0);
                },

                //Math
                add: function() {
                    engine.push(engine.pop() + engine.pop());
                },
                subtract: function() {
                    var rArg = engine.pop();
                    var lArg = engine.pop();
                    var result = lArg - rArg;
                    engine.push(result);
                },
                divide: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    var result = Math.floor(l / r);
                    engine.push(result);
                },
                multiply: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    var result = l * r;
                    engine.push(result);
                },
                mod: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    var result = l % r;
                    engine.push(result);
                },
                slashMod: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    var remainder = l % r;
                    var result = Math.floor(l / r);
                    engine.push(remainder);
                    engine.push(result);
                },
                starSlash: function() {
                    var divisor = engine.pop();
                    var r = engine.pop();
                    var l = engine.pop();

                    var result = Math.floor((l * r) / divisor);
                    engine.push(result);
                },
                abs: function() {
                    var arg = engine.pop();
                    engine.push(Math.abs(arg));
                },
                min: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    if (r < l) {
                        engine.push(r)
                    }
                    else {
                        engine.push(l);
                    }
                },
                max: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    if (r < l) {
                        engine.push(l)
                    }
                    else {
                        engine.push(r);
                    }
                },
                onePlus: function() {
                    var arg = engine.pop() + 1;
                    engine.push(arg);
                },
                oneMinus: function() {
                    var arg = engine.pop() - 1;
                    engine.push(arg);
                },

                twoPlus: function() {
                    var arg = engine.pop() + 2;
                    engine.push(arg);
                },
                twoMinus: function() {
                    var arg = engine.pop() - 2;
                    engine.push(arg);
                },

                twoMultiply: function() {
                    var arg = engine.pop() * 2;
                    engine.push(arg);
                },
                twoDivide: function() {
                    var arg = engine.pop() / 2;
                    engine.push(arg);
                },
                //Pointer functions
                spFetch: function() {
                    engine.push(engine.sp);
                },

                spOrgin: function() {
                    engine.push(engine.spOrgin);
                },
                //condition operators
                zeroEqual: function() {
                    engine.pop() == 0 ? Forth.True() : Forth.False();
                },
                zeroLess: function() {
                    engine.pop() < 0 ? Forth.True() : Forth.False();
                },

                zeroGreater: function() {
                    engine.pop() > 0 ? Forth.True() : Forth.False();
                },

                equal: function() {
                    engine.pop() == engine.pop() ? Forth.True() : Forth.False();
                },

                notEqual: function() {
                    engine.pop() != engine.pop() ? Forth.True() : Forth.False();
                },

                greaterThan: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    l > r ? Forth.True() : Forth.False();
                },

                greaterThanOrEqual: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    l >= r ? Forth.True() : Forth.False();
                },

                lessThan: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    l < r ? Forth.True() : Forth.False();
                },

                lessThanOrEqual: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    l <= r ? Forth.True() : Forth.False();
                },

                bitwiseOr: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    engine.push(l | r);
                },

                bitwiseAnd: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    engine.push(l & r);
                },

                bitwiseXor: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    engine.push(l ^ r);
                },

                bitwiseNot: function() {
                    var a = engine.pop();
                    engine.push(~a);
                },

                logicalAnd: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    engine.push(l > 0 && r > 0 ? 1 : 0);
                },

                logicalOr: function() {
                    var r = engine.pop();
                    var l = engine.pop();
                    engine.push(l > 0 || r > 0 ? 1 : 0);
                },

                logicalNot: function() {
                    var a = engine.pop();
                    engine.push(a == 0 ? 1 : 0);
                },

                call: function() {
                    var word = new ForthWord();
                    word.name = null;
                    word.code = new Array();

                    do {
                        var arg = engine.getInterpretValue();
                        if (word.name == null) {
                            word.name = arg;
                        }
                        else {
                            word.code.push(arg);
                        }
                    } while (arg != ";");
                    if (word.code.length > 0) {
                        engine.addToDict(word);
                    }
                },

                end: function() {
                    endSub();
                },

                dotget: function() {
                    engine.write(engine.pop() + " ");
                },
                cr: function() {
                    engine.write("\n");
                },

                space: function() {
                    engine.write(" ");
                },

                spaces: function() {
                    var arg = engine.pop();
                    for (count = 0; count < arg; count++) {
                        Forth.space();
                    }
                },

                emit: function() {
                    engine.write(String.fromCharCode(engine.pop()));
                },

                If: function() {
                    var arg = engine.pop();
                    if (arg != 0) {
                        return;
                    }
                    //move codepointer to paired else or then
                    var ifStack = new Array();
                    do {
                        var word = engine.getInterpretValue();
                        if (word != null) {
                            word = word.toLowerCase();
                            if (word == "if") {
                                ifStack.push("if");
                            }
                            else if (word == "else" || word == "then") {
                                if (ifStack.length == 0) {
                                    return;
                                }
                                ifStack.pop();
                            }
                        }
                    } while (word != null);
                    throw Error("No matching else or then found for if");
                },

                Else: function() {
                    //move codepointer to paired else or then
                    var ifStack = new Array();
                    do {
                        var word = engine.getInterpretValue();
                        if (word != null) {
                            word = word.toLowerCase();
                            if (word == "if") {
                                ifStack.push("if");
                            }
                            else if (word == "then") {
                                if (ifStack.length == 0) {
                                    return;
                                }
                                ifStack.pop();
                            }
                        }
                    } while (word != null);
                    throw Error("No matching then found for else");

                },

                Then: function() {
                },

                tor: function() {
                    engine.rpush(engine.pop());
                },
                I: function() {
                    engine.push(engine.rpeek());
                },

                Do: function() {
                    Forth.swap();
                    Forth.tor();
                    Forth.tor();
                    //add this 'Do' address to the loop stack
                    engine.loopStack.push(engine.codePointer - 1);
                },

                Loop: function() {
                    var index = engine.rpop();
                    var limit = engine.rpeek();
                    var done = false;

                    done = (limit - (++index)) == 0;

                    if (done == false) {
                        //TODO goto do
                        engine.rpush(index);
                        var doIndex = engine.getLoopIndex();
                        if (doIndex == null) {
                            throw Error("No matching do for loop");
                        }
                        engine.codePointer = doIndex + 1;
                        return;
                    }
                    engine.rpop();
                    engine.loopStack.pop();
                },

                PlusLoop: function() {
                    var count = engine.pop();
                    var index = engine.rpop();
                    var limit = engine.rpeek();
                    var done = false;
                    index = index + count;
                    if (count >= 0) {
                        done = (limit - index) <= 0;
                    }
                    else {
                        done = (limit + index) >= 0;
                    }

                    if (done == false) {
                        //TODO goto do
                        engine.rpush(index);
                        var doIndex = engine.getLoopIndex();
                        if (doIndex == null) {
                            throw Error("No matching do for loop");
                        }
                        engine.codePointer = doIndex + 1;
                        return;
                    }
                    engine.rpop();
                    engine.loopStack.pop();
                },

                leave: function() {
                    var arg = null;
                    do {
                        arg = engine.getInterpretValue();
                        if (arg != null) {
                            arg = arg.toLowerCase();
                            if(arg == "loop" || arg == "+loop") {
                                engine.rpop();
                                engine.rpop();
                                engine.loopstack.pop();
                               return;
                            }
                        }
                    }while(arg != null);
                     throw Error("No matching loop for do");
                },

                begin: function() {
                    engine.loopStack.push(engine.codePointer - 1);
                },

                until: function() {
                    var arg = engine.pop();
                    //if the arg is true we are done
                    if(arg > 0) {
                        engine.loopStack.pop();
                    }
                    else {
                        var bLoop = engine.loopStack.pop();
                        engine.codePointer = bLoop;
                        engine.loopStack.push(bLoop);
                    }
                },

                While: function() {
                    var arg = engine.pop();
                    if (arg <= 0) {
                        engine.loopStack.pop();
                        var ele = null;
                        do{
                            ele = engine.getInterpretValue();
                            if(ele != null) {
                                ele = ele.toLowerCase();
                                if (ele == "repeat") {
                                    return;
                                }
                            }
                        }while (ele != null);
                        throw Error("No matching repeat for while");
                    }
                },

                repeat: function() {
                     //go back to begin
                     var bLoop = engine.loopStack.pop();
		            engine.codePointer = bLoop;
                     engine.loopStack.push(bLoop);
                },
                
                forget: function() {
                    var strWord = engine.getInterpretValue();
                    if (strWord == null) {
                        throw new Error("No word found to forget");
                    }
                    var word = engine.latest;
                    var lastWord = null;
                    while(word != null) {
                        if(word.name.toLowerCase() == strWord.toLowerCase()) {
                            if (lastWord == null) {
                                engine.latest = word.next;
                            }
                            else {
                                lastWord.next = word.next;
                            }
                            return;
                        }
                        lastWord = word;
                        word = word.next;
                    }
                },

                quit: function() {
                    var sysDic = engine.systemDic;
                    var console = engine.console;
                    var userDic = engine.latest;
                    var cIndex = engine.consoleLastIndex;

                    engine = new ForthMachine();
                    engine.systemDic = sysDic;
                    engine.console = console;
                    engine.latest = userDic;
                    engine.consoleLastIndex = cIndex;
                },
                
                bye: function() {
                    engine.write(" bye");
                    Forth.quit();
                },

                interpret: function() {
                    try{
                    if (engine.endOfProgram()) {
                        return 0;
                    }

                    var arg = engine.getInterpretValue();

                    //is string const
                    arg = new String(arg);
                    if (arg.startsWith(".\"")) {
                        var s = arg.replace(/^\."/, "");
                        s = s.replace(/"$/, "");
                        engine.write(s);
                        return 1;
                    }
                    //search system dictionary
                    var sysWord = engine.systemDic.getWord(arg);
                    if (sysWord != null) {
                        execute(sysWord);
                        //Forth.interpret();
                        return 1;
                    }

                    //search user dictionary
                    var userWord = engine.searchUserDict(arg);
                    if (userWord != null) {
                        //push onto execution stack
                        addSub(userWord);
                        //Forth.interpret();
                        return 1;
                    }
                    //convert to number

                    var num = parseInt(arg);
                    if (!isNaN(num)) {
                        Forth.lit(num);
                        //Forth.interpret();
                        return 1;
                    }
                    //fail write output
                    engine.write(" ?" + arg + "\n");
                    Forth.quit();
                    return 0;
                    }
                    catch (err) {

                        engine.write(err.message + "\n");
                        Forth.quit();
                        return 0;
                    }
                    
                },
                
                pace: function() {
                    //sets the pace at which intructions are executed. Useful in when forth
                    //is working or setting other parts of the DOM
                    engine.interrupt = engine.pop();
                },

                eval: function(instruct) {
                    engine.executionStack = new Array();
                    engine.codePointer = 0;
                    var parser = new ForthParser();
                    engine.executionStack = parser.getIntructions(instruct);
                    engine.executionStack.push("SPACE");
                    engine.executionStack.push(".\"ok\"");
                    engine.executionStack.push("cr");
                    while (!engine.endOfProgram()) {
                        Forth.interpret();
                    } 
                },
                
                eval_i: function(instruct) {
                    engine.executionStack = new Array();
                    engine.codePointer = 0;
                    var parser = new ForthParser();
                    engine.executionStack = parser.getIntructions(instruct);
                    engine.executionStack.push("SPACE");
                    engine.executionStack.push(".\"ok\"");
                    engine.executionStack.push("cr");
                    Forth.run_loop();
                },
                
                run_loop: function() {
                    var arg = Forth.interpret();
                    if (arg == 1) {
                        setTimeout("Forth.run_loop();", engine.interrupt);
                    }
                }
                
            };
        } ();
    }

