Exemple #1
0
        public SpellburstRuntimeError Run()
        {
            var mode = ReadMode.WaitIMP;

            var IMP     = new SpellburstIMP();
            var Command = new SpellburstCommand();
            var Number  = new SpellburstNumber();
            var Label   = new SpellburstLabel();

            var ProgramCounter = 0;

            var RoutineMaxDepth = 31;
            var RoutineNowDepth = 0;

            var LabelTemp = 0;

            Action reset = () => { IMP.Reset(); Command.Reset(); Number.Reset(); Label.Reset(); mode = ReadMode.WaitIMP; };

            while (Codes.Count != 0)
            {
                if (ProgramCounter >= Codes.Count)
                {
                    break;
                }
                var first = Codes[ProgramCounter];


                switch (mode)
                {
                case ReadMode.WaitIMP:
                    IMP.AddIMP(first);

                    if (IMP.IsEqualTo("S"))
                    {
                        mode = ReadMode.WaitCommand;
                    }
                    if (IMP.IsEqualTo("N"))
                    {
                        mode = ReadMode.WaitCommand;
                    }
                    if (IMP.IsEqualTo("TS"))
                    {
                        mode = ReadMode.WaitCommand;
                    }
                    if (IMP.IsEqualTo("TN"))
                    {
                        mode = ReadMode.WaitCommand;
                    }
                    if (IMP.IsEqualTo("TT"))
                    {
                        mode = ReadMode.WaitCommand;
                    }
                    break;

                case ReadMode.WaitCommand:
                    Command.AddCommand(first);

                    //楽なのを先に処理
                    if (IMP.IsEqualTo("TT"))
                    {
                        //スタックの値をアドレスに格納
                        if (Command.IsEqualTo("S"))
                        {
                            if (CheckStackEmpty())
                            {
                                return(new SpellburstRuntimeError(ErrorType.StackIsEmpty));
                            }
                            Heap = IntegerStack.Peek();
                            reset();
                        }
                        //アドレスの値をスタックに積む
                        if (Command.IsEqualTo("T"))
                        {
                            IntegerStack.Push(Heap);
                            reset();
                        }
                    }
                    //ここから本題

                    //スタック操作
                    if (IMP.IsEqualTo("S"))
                    {
                        //数値をスタックにプッシュ(ReadMode.InputIntegerの方で処理は行う)
                        if (Command.IsEqualTo("S"))
                        {
                            mode = ReadMode.InputInteger;
                        }
                        //スタックトップを複製
                        if (Command.IsEqualTo("NS"))
                        {
                            IntegerStack.Push(IntegerStack.Peek());
                            reset();
                        }
                        //スタックの1番目と2番目を交換
                        if (Command.IsEqualTo("NT"))
                        {
                            var e1 = IntegerStack.Pop();
                            var e2 = IntegerStack.Pop();
                            IntegerStack.Push(e1);
                            IntegerStack.Push(e2);

                            reset();
                        }
                        //スタックトップを破棄
                        if (Command.IsEqualTo("NN"))
                        {
                            IntegerStack.Pop();

                            reset();
                        }
                    }
                    //四則演算+余
                    if (IMP.IsEqualTo("TS"))
                    {
                        //加減乗除余
                        if (Command.IsEqualTo("SS"))
                        {
                            Calc((e1, e2) => e1 + e2);
                            reset();
                        }
                        if (Command.IsEqualTo("ST"))
                        {
                            Calc((e1, e2) => e1 - e2);
                            reset();
                        }
                        if (Command.IsEqualTo("SN"))
                        {
                            Calc((e1, e2) => e1 * e2);
                            reset();
                        }
                        if (Command.IsEqualTo("TS"))
                        {
                            Calc((e1, e2) => e1 / e2);
                            reset();
                        }
                        if (Command.IsEqualTo("TT"))
                        {
                            Calc((e1, e2) => e1 % e2);
                            reset();
                        }
                    }

                    //ラベル
                    if (IMP.IsEqualTo("N"))
                    {
                        //ラベル定義
                        if (Command.IsEqualTo("SS"))
                        {
                            mode = ReadMode.InputLabel; LabelTemp = ProgramCounter;
                        }
                        //サブルーチン呼び出し
                        if (Command.IsEqualTo("ST"))
                        {
                            //階層チェック
                            if (++RoutineNowDepth > RoutineMaxDepth)
                            {
                                return(new SpellburstRuntimeError(ErrorType.SubRoutineLevelTooDeep));
                            }
                            mode      = ReadMode.InputLabel;
                            LabelTemp = ProgramCounter;
                        }
                        //無条件ジャンプ
                        if (Command.IsEqualTo("SN"))
                        {
                            mode = ReadMode.InputLabel; LabelTemp = ProgramCounter;
                        }
                        //スタックトップがゼロならジャンプ
                        if (Command.IsEqualTo("TS"))
                        {
                            mode = ReadMode.InputLabel; LabelTemp = ProgramCounter;
                        }
                        //スタックトップが負ならジャンプ
                        if (Command.IsEqualTo("TT"))
                        {
                            mode = ReadMode.InputLabel; LabelTemp = ProgramCounter;
                        }
                        //サブルーチン終了
                        if (Command.IsEqualTo("TN"))
                        {
                            //階層チェック
                            if (--RoutineNowDepth < 0)
                            {
                                return(new SpellburstRuntimeError(ErrorType.ReturnInNonSubroutine));
                            }
                            ProgramCounter = CallFrom.Pop();

                            reset();
                        }
                        //プログラム終了
                        if (Command.IsEqualTo("NN"))
                        {
                            mode = ReadMode.Finish;
                        }
                    }
                    //入出力
                    if (IMP.IsEqualTo("TN"))
                    {
                        //スタックトップの文字を出力
                        if (Command.IsEqualTo("SS"))
                        {
                            var e = IntegerStack.Peek();
                            Console.Write(Convert.ToChar(e));

                            reset();
                        }
                        //スタックトップの数値を出力
                        if (Command.IsEqualTo("ST"))
                        {
                            var e = IntegerStack.Peek();
                            Console.Write(e);

                            reset();
                        }
                        //文字を読み込みアドレスに格納
                        if (Command.IsEqualTo("TS"))
                        {
                            Heap = Console.Read();

                            reset();
                        }
                        //数値を読み込みアドレスに格納
                        if (Command.IsEqualTo("TN"))
                        {
                            Heap = int.Parse(Console.ReadLine());

                            reset();
                        }
                    }
                    break;

                case ReadMode.InputInteger:
                    if (first.Equals(SpellCode.NewLine))
                    {
                        //スタックに数値をpushする(preprocessなのでしない)
                        IntegerStack.Push(Number.Result);

                        reset();
                    }

                    Number.AddNumber(first);
                    break;

                case ReadMode.InputLabel:
                    if (first.Equals(SpellCode.NewLine))
                    {
                        //ラベル定義
                        if (Command.IsEqualTo("SS"))
                        {
                            //何もしない
                        }
                        //サブルーチン呼び出し
                        if (Command.IsEqualTo("ST"))
                        {
                            var row = LabelDict[Label.Result] - 1;
                            CallFrom.Push(ProgramCounter);
                            ProgramCounter = row;
                        }
                        //無条件ジャンプ
                        if (Command.IsEqualTo("SN"))
                        {
                            ProgramCounter = LabelDict[Label.Result] - 1;
                        }
                        //ゼロならジャンプ
                        if (Command.IsEqualTo("TS"))
                        {
                            if (IntegerStack.Peek() == 0)
                            {
                                ProgramCounter = LabelDict[Label.Result] - 1;
                            }
                        }
                        //負ならジャンプ
                        if (Command.IsEqualTo("TT"))
                        {
                            if (IntegerStack.Peek() < 0)
                            {
                                ProgramCounter = LabelDict[Label.Result] - 1;
                            }
                        }
                        reset();
                    }

                    Label.Add(first);
                    break;

                case ReadMode.Finish:
                    Codes.Clear();
                    break;
                }
                ProgramCounter++;
            }

            return(new SpellburstRuntimeError(ErrorType.Success));
        }