Пример #1
0
        public SpellburstCompileError PreProcess()
        {
            string[] sa = Code.Replace(Environment.NewLine, "\n").Split('\n');

            //行数過多
            if (sa.Length >= 8)
            {
                return(new SpellburstCompileError(ErrorType.TooManyNewLine));
            }
            //禁止ワード
            if (ContainsFWords(Code))
            {
                return(new SpellburstCompileError(ErrorType.FWord));
            }

            //解釈処理
            Code = string.Join("", sa);

            var iter  = new SpellburstIterator(Code);
            var queue = new Queue <SpellCode>();

            var i = new[] { SpellCode.None };

            while ((i = iter.NextCode()) != null)
            {
                queue.EnqueueRange(i);
            }

            Interpreter.Codes = new List <SpellCode>(queue);

            //Console.WriteLine(queue.Select(e => e.ToString()).Aggregate(",", (s, e) => s += e + ","));

            var mode = ReadMode.WaitIMP;

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

            var ProgramCounter = 0;

            var SubroutineCall = 0;
            var SubroutineEnd  = 0;
            var LabelTemp      = 0;

            var labelDict     = new Dictionary <string, int>();
            var labelJumpDict = new List <string>();

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

            while (queue.Count != 0)
            {
                var first = queue.Dequeue();

                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"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("T"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("N"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                    }
                    //ここから本題
                    if (IMP.IsEqualTo("S"))
                    {
                        if (Command.IsEqualTo("S"))
                        {
                            mode = ReadMode.InputInteger;
                        }
                        if (Command.IsEqualTo("NS"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("NT"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("NN"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }

                        if (Command.IsEqualTo("T"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                    }
                    if (IMP.IsEqualTo("TS"))
                    {
                        if (Command.IsEqualTo("SS"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("ST"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("SN"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("TS"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("TT"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }

                        if (Command.IsEqualTo("TN"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                        if (Command.IsEqualTo("N"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                    }
                    if (IMP.IsEqualTo("N"))
                    {
                        if (Command.IsEqualTo("SS"))
                        {
                            mode = ReadMode.InputLabel; LabelTemp = ProgramCounter;
                        }
                        if (Command.IsEqualTo("ST"))
                        {
                            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"))
                        {
                            mode = ReadMode.WaitIMP; SubroutineEnd++; reset();
                        }
                        if (Command.IsEqualTo("NN"))
                        {
                            mode = ReadMode.Finish;
                        }

                        if (Command.IsEqualTo("NS"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                        if (Command.IsEqualTo("NT"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                        //labelJumpDict
                    }
                    if (IMP.IsEqualTo("TN"))
                    {
                        if (Command.IsEqualTo("SS"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("ST"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("TS"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }
                        if (Command.IsEqualTo("TN"))
                        {
                            mode = ReadMode.WaitIMP; reset();
                        }

                        if (Command.IsEqualTo("SN"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                        if (Command.IsEqualTo("TT"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                        if (Command.IsEqualTo("N"))
                        {
                            return(new SpellburstCompileError(ErrorType.CommandNotFound, ProgramCounter));
                        }
                    }
                    break;

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

                        mode = ReadMode.WaitIMP;
                        reset();
                        break;
                    }

                    Number.AddNumber(first);
                    break;

                case ReadMode.InputLabel:
                    if (first.Equals(SpellCode.NewLine))
                    {
                        //ラベル定義
                        if (Command.IsEqualTo("SS"))
                        {
                            if (labelDict.ContainsKey(Label.Result))
                            {
                                return(new SpellburstCompileError(ErrorType.LabelIsAlreadyDefined));
                            }
                            labelDict.Add(Label.Result, LabelTemp);
                        }
                        //サブルーチン呼び出し
                        if (Command.IsEqualTo("ST"))
                        {
                            labelJumpDict.Add(Label.Result);
                            SubroutineCall++;
                        }
                        //無条件ジャンプ
                        if (Command.IsEqualTo("SN"))
                        {
                            labelJumpDict.Add(Label.Result);
                        }
                        //ゼロならジャンプ
                        if (Command.IsEqualTo("TS"))
                        {
                            labelJumpDict.Add(Label.Result);
                        }
                        //負ならジャンプ
                        if (Command.IsEqualTo("TT"))
                        {
                            labelJumpDict.Add(Label.Result);
                        }
                        mode = ReadMode.WaitIMP;
                        reset();
                    }

                    Label.Add(first);
                    break;

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

            foreach (var l in labelJumpDict)
            {
                if (!labelDict.ContainsKey(l))
                {
                    return(new SpellburstCompileError(ErrorType.InvalidLabelJump));
                }
            }
            Interpreter.LabelDict = new Dictionary <string, int>(labelDict);

            return(new SpellburstCompileError(ErrorType.Success));
        }
Пример #2
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));
        }