protected void OnLog(string sMsg)
 {
     DebugPrint?.Invoke(sMsg);
 }
        private void Interpret()
        {
            object[] operation;
            object   akkumulator;
            object   register;

            scopes = new Scopes();
            scopes.PushScope(external);
            scopes.PushScope();

            int startTime = Environment.TickCount;

            Cancel  = false;
            running = true;

            pc = 0;

            bool accepted;
            // bool continues;
            object xPos;
            object defaultRenamed;
            object yPos;


            while ((pc < code.Count - 1) & running)
            {
                akkumulator = null;
                register    = null;

                operation = (Object[])code[pc];

                switch ((Opcodes)operation.GetValue(0))
                {
                // Konstante allozieren
                case Opcodes.opAllocConst:
                {
                    // Parameter:    Name der Konstanten; Wert
                    scopes.Allocate(operation.GetValue(1).ToString(), operation.GetValue(2).ToString(), Identifier.IdentifierTypes.idConst);
                    break;
                }

                // Variable allozieren
                case Opcodes.opAllocVar:
                {
                    // Parameter:    Name der Variablen
                    scopes.Allocate(operation.GetValue(1).ToString());
                    break;
                }

                // Wert auf den Stack schieben
                case Opcodes.opPushValue:
                {
                    // Parameter:    Wert
                    scopes.Push(operation.GetValue(1));
                    break;
                }

                // Wert einer Variablen auf den Stack schieben
                case Opcodes.opPushVariable:
                {
                    // Parameter:    Variablenname
                    string name;
                    try
                    {
                        var tmp = operation.GetValue(1);
                        if (tmp.GetType() == typeof(Identifier))
                        {
                            name = ((Identifier)tmp).value.ToString();
                        }
                        else
                        {
                            name = tmp.ToString();
                        }
                        register = scopes.Retrieve(name);
                    }
                    catch (Exception)
                    {
                        // Variable nicht alloziert, also bei Host nachfragen
                        accepted = false;
                        Retrieve?.Invoke(operation.GetValue(1).ToString(), register.ToString(), accepted);
                        if (!accepted)
                        {
                            // der Host weiss nichts von der Var. Implizit anlegen tun wir
                            // sie aber nicht, da sie hier auf sie sofort lesend zugegriffen
                            // würde

                            running = false;
                            ErrorObject.Raise((int)InterpreterError.runErrors.errUnknownVar, "Code.Run", "Unknown variable '" + operation.GetValue(1) + "'", 0, 0, 0);
                        }
                    }

                    if (register == null)
                    {
                        running = false;
                        ErrorObject.Raise((int)InterpreterError.runErrors.errUninitializedVar, "Code.Run", "Variable '" + operation.GetValue(1) + "' not hasn´t been assigned a Value yet", 0, 0, 0);
                    }
                    else
                    {
                        if (register.GetType() == typeof(Identifier))
                        {
                            scopes.Push(((Identifier)register).value);
                        }
                        else
                        {
                            scopes.Push(register.ToString());
                        }
                    }

                    break;
                }

                // entfernt obersten Wert vom Stack
                case Opcodes.opPop:
                {
                    scopes.PopScopes();
                    break;
                }

                // legt den n-ten Stackwert zuoberst auf den Stack
                case Opcodes.opPopWithIndex:
                {
                    // Parameter:    Index in den Stack (von oben an gezählt: 0..n)
                    object result;
                    register = scopes.Pop(Convert.ToInt32(operation.GetValue(1)));
                    if (register is Identifier)
                    {
                        result = ((Identifier)register).value;
                    }
                    else
                    {
                        result = register;
                    }
                    scopes.Push(result);
                    break;
                }

                // Wert auf dem Stack einer Variablen zuweisen
                case Opcodes.opAssign:
                {
                    // Parameter:    Variablenname
                    // Stack:        der zuzuweisende Wert

                    object result;
                    register = scopes.Pop();
                    if (register is Identifier)
                    {
                        result = ((Identifier)register).value;
                    }
                    else
                    {
                        result = register;
                    }
                    if (!scopes.Assign(operation.GetValue(1).ToString(), result))
                    {
                        ;
                    }
                    {
                        // Variable nicht alloziert, also Host anbieten
                        accepted = false;


                        Assign?.Invoke(operation.GetValue(1).ToString(), result.ToString(), ref accepted);
                        if (!accepted)
                        {
                            // Host hat nicht mit Var am Hut, dann legen wir
                            // sie eben selbst an
                            scopes.Allocate(operation.GetValue(1).ToString(), result.ToString());
                        }
                    }

                    break;
                }

                case Opcodes.opAdd:
                case Opcodes.opSub:
                case Opcodes.opMultiplication:
                case Opcodes.opDivision:
                case Opcodes.opDiv:
                case Opcodes.opMod:
                case Opcodes.opPower:
                case Opcodes.opStringConcat:
                case Opcodes.opOr:
                case Opcodes.opAnd:
                case Opcodes.opEq:
                case Opcodes.opNotEq:
                case Opcodes.oplt:
                case Opcodes.opLEq:
                case Opcodes.opGt:
                case Opcodes.opGEq:
                    BinaryMathOperators(operation, akkumulator, register);
                    break;

                case Opcodes.opNegate:
                case Opcodes.opNot:
                case Opcodes.opFactorial:
                case Opcodes.opSin:
                case Opcodes.opCos:
                case Opcodes.opTan:
                case Opcodes.opATan:
                    UnaryMathOperators(operation);
                    break;

                case Opcodes.opDebugPrint:
                {
                    string msg = string.Empty;


                    register = scopes.PopScopes();
                    if (register != null)
                    {
                        msg = ((Identifier)register).value.ToString();
                    }

                    DebugPrint?.Invoke(msg);


                    break;
                }

                case Opcodes.opDebugClear:
                {
                    DebugClear?.Invoke();
                    break;
                }

                case Opcodes.opDebugShow:
                {
                    DebugShow?.Invoke();
                    break;
                }

                case Opcodes.opDebugHide:
                {
                    DebugHide?.Invoke();
                    break;
                }

                case Opcodes.opMessage:
                {
                    try
                    {
                        string msg  = string.Empty;
                        int    type = 0;
                        register    = scopes.PopScopes();       // Message
                        akkumulator = scopes.PopScopes().value; // Type
                        if (register is Identifier)
                        {
                            if (register != null)
                            {
                                if (register.GetType() == typeof(Identifier))
                                {
                                    msg = ((Identifier)register).value.ToString();
                                }
                                else
                                {
                                    msg = register.ToString();
                                }
                            }
                        }


                        if (akkumulator != null)
                        {
                            if (akkumulator.GetType() == typeof(Identifier))
                            {
                                type = Convert.ToInt32(((Identifier)akkumulator).value);
                            }
                            else
                            {
                                type = Convert.ToInt32(akkumulator);
                            }
                        }


                        Message?.Invoke(type, msg);
                    }
                    catch (Exception)
                    {
                        Message?.Invoke(-1, string.Empty);
                    }

                    break;
                }

                case Opcodes.opMsgbox:
                {
                    if (!AllowUi)
                    {
                        running = false;
                        ErrorObject.Raise((int)InterpreterError.runErrors.errNoUIallowed, "Code.Run", "MsgBox-Statement cannot be executed when no UI-elements are allowed", 0, 0, 0);
                    }

                    register    = scopes.PopScopes().value; // Title
                    akkumulator = scopes.PopScopes().value; // Buttons

                    try
                    {
                        // TODO:InputBox  // scopes.Push(MsgBox(scopes.Pop, (MsgBoxStyle)Akkumulator.ToString(), Register));
                    }
                    catch (Exception ex)
                    {
                        running = false;
                        ErrorObject.Raise((int)InterpreterError.runErrors.errMath, "Code.Run", "Error during MsgBox-call: " + ex.HResult + " (" + ex.Message + ")", 0, 0, 0);
                    }

                    break;
                }

                case Opcodes.opDoEvents:
                {
                    break;
                }

                case Opcodes.opInputbox:
                {
                    if (!AllowUi)
                    {
                        running = false;
                        ErrorObject.Raise((int)InterpreterError.runErrors.errNoUIallowed, "Code.Run", "Inputbox-Statement cannot be executed when no UI-elements are allowed", 0, 0, 0);
                    }

                    yPos           = scopes.PopScopes().value;
                    xPos           = scopes.PopScopes().value;
                    defaultRenamed = scopes.PopScopes().value;
                    register       = scopes.PopScopes().value;
                    akkumulator    = scopes.PopScopes().value;

                    try
                    {
                        // TODO:InputBox
                        //string Anwert = Microsoft.VisualBasic.Interaction.InputBox(Akkumulator.ToString(), Register.ToString(), defaultRenamed.ToString(), Convert.ToInt32(xPos), Convert.ToInt32(yPos));
                        //scopes.Push(Anwert);
                    }
                    catch (Exception ex)
                    {
                        running = false;
                        ErrorObject.Raise((int)InterpreterError.runErrors.errMath, "Code.Run", "Error during MsgBox-call: " + ex.HResult + " (" + ex.Message + ")", 0, 0, 0);
                    }

                    break;
                }

                case Opcodes.opJump:
                {
                    pc = Convert.ToInt32(operation.GetValue(1)) - 1;
                    break;
                }

                case Opcodes.opJumpTrue:
                {
                    akkumulator = scopes.PopScopes().value;
                    if (Convert.ToBoolean(akkumulator))
                    {
                        pc = Convert.ToInt32(operation.GetValue(1)) - 1;
                    }
                    break;
                }

                case Opcodes.opJumpFalse:
                {
                    akkumulator = scopes.PopScopes().value;
                    if (!Convert.ToBoolean(akkumulator))
                    {
                        pc = Convert.ToInt32(operation.GetValue(1)) - 1;
                    }
                    break;
                }

                case Opcodes.opJumpPop:
                {
                    pc = Convert.ToInt32(scopes.PopScopes().value) - 1;
                    break;
                }

                case Opcodes.opPushScope:
                {
                    scopes.PushScope();
                    break;
                }

                case Opcodes.opPopScope:
                {
                    scopes.PopScopes();
                    break;
                }

                case Opcodes.opCall:
                {
                    scopes.Allocate("~RETURNADDR", (pc + 1).ToString(), Identifier.IdentifierTypes.idConst);
                    pc = Convert.ToInt32(operation.GetValue(1)) - 1;
                    break;
                }

                case Opcodes.opReturn:
                {
                    pc = Convert.ToInt32(Convert.ToDouble(scopes.Retrieve("~RETURNADDR").value, CultureInfo.InvariantCulture) - 1);
                    break;
                }
                }


                pc = pc + 1; // zum nächsten Befehl

                // wurde Interpretation unterbrochen?
                if (Cancel)
                {
                    running = false;
                    ErrorObject.Raise((int)InterpreterError.runErrors.errCancelled, "Code.Run", "Code execution aborted", 0, 0, 0);
                }

                // Timeout erreicht?
                var tickPassed = (Environment.TickCount - startTime);
                if (CodeTimeout > 0 && tickPassed >= CodeTimeout)
                {
                    running = false;
                    ErrorObject.Raise((int)InterpreterError.runErrors.errTimedOut, "Code.Run", "Timeout reached: code execution has been aborted", 0, 0, 0);
                }
            }

            running = false;
        }
 private void OnDebugPrint(string s)
 {
     DebugPrint?.Invoke(this, s);
 }