[QUIZ#3] Spyke (C#)


Spyke

Capoeirista
Premium-User
#1
Zum testen am besten den letzten Dateianhang dieses Thread verwenden.

Die erste Version des Interpreters läuft mit Hilfe von Regular Expression

Der Interpreter
C#:
    internal class BFInterpreter
    {
        /// <summary>
        /// wird aufgerufen wenn eine Eingabe erwartet wird
        /// </summary>
        /// <returns>ASCII Wert des eingegebenen Zeichens</returns>
        public delegate int Input();
        /// <summary>
        /// wird aufgerufen wenn eine Ausgabe erwartet wird
        /// </summary>
        /// <param name="value">ASCII Wert des auszugebenen Zeichens</param>
        public delegate void Output(int value);

        /// <summary>
        /// Objekt wird erstellt
        /// </summary>
        /// <param name="input">Methode für Eingabe</param>
        /// <param name="output">Methode für Ausgabe</param>
        internal BFInterpreter(Input input, Output output)
        {
            this.input = input;
            this.output = output;
        }

        /// <summary>
        /// Interpreter wird gestartet
        /// </summary>
        /// <param name="s">Zeichenkette die untersucht werden soll</param>
        public void Parse(string s)
        {
            Dictionary<int, int> band = new Dictionary<int, int>();
            int position = 0;

            band.Add(position, 0);

            Parse(band, ref position, s);
        }

        /// <summary>
        /// analysiert die Zeichenkette
        /// </summary>
        /// <param name="band">Speicher</param>
        /// <param name="position">Position im Speicher</param>
        /// <param name="s">zu untersuchende Zeichenkette</param>
        private void Parse(Dictionary<int, int> band, ref int position, string s)
        {
            //Zeichen '+'
            string pInkr = @"(?'inkr'\+{1,})";
            //Zeichen '-'
            string pDekr = @"(?'dekr'-{1,})";
            //Zeichen '>'
            string pPointInkr = @"(?'PointInkr'>{1,})";
            //Zeichen '<'
            string pPointDekr = @"(?'PointDekr'<{1,})";
            //Zeichen '.' (Ausgabe)
            string pOutput = @"(?'output'\.)";
            //Zeichen ',' (Eingabe)
            string pInput = @"(?'input',)";
            //Zeichen '[' (Blockbeginn)
            string pBlockBeginn = @"(?'blockbeginn'\[.*)";

            //Hilfspattern für die übrigen Zeichen
            string pCheck = @"[^\+\-\[\]\<\>\.\,]*";

            //Zeichenkette untersuchen
            foreach (Match m in Regex.Matches(s, pInkr + "|" + pDekr + "|" + pPointInkr + "|" + pPointDekr + "|" + pOutput + "|" + pInput + "|" + pBlockBeginn + "|" + pCheck, RegexOptions.Singleline))
            {
                if (m.Groups["inkr"].Success) //Zeichen '+'
                {
                    band[position] += m.Groups["inkr"].Value.Length;
                    if (band[position] > 255)
                        band[position] = 0;
                }
                else if (m.Groups["dekr"].Success) //Zeichen '-'
                {
                    band[position] -= m.Groups["dekr"].Value.Length;
                    if (band[position] < 0)
                        band[position] = 255;
                }
                else if (m.Groups["PointInkr"].Success) //Zeichen '>'
                {
                    position += m.Groups["PointInkr"].Value.Length;
                    if (!band.ContainsKey(position))
                        band.Add(position, 0);
                }
                else if (m.Groups["PointDekr"].Success) //Zeichen '<'
                {
                    position -= m.Groups["PointDekr"].Value.Length;
                    if (!band.ContainsKey(position))
                        band.Add(position, 0);
                }
                else if (m.Groups["output"].Success) //Zeichen '.' (Ausgabe)
                    output(band[position]);
                else if (m.Groups["input"].Success) //Zeichen ',' (Eingabe)
                    band[position] = input();
                else if (m.Groups["blockbeginn"].Success)
                {
                    string block = m.Groups["blockbeginn"].Value.Substring(1);
                    int endBlock = EndBlock(block);
                    if (endBlock > -1)
                    {
                        string block2 = block.Substring(0, endBlock);
                        while (band[position] != 0)
                            Parse(band, ref position, block2);
                    }

                    if (endBlock < block.Length) //ist noch nicht das Ende, weiter parsen
                        Parse(band, ref position, block.Substring(endBlock));
                }
            }
        }

        /// <summary>
        /// sucht Ende des aktuellen Blockes
        /// </summary>
        private int EndBlock(string block)
        {
            int beginnCounter = 0; //Prüf Variable für innere Blöcke
            for (int i = 0; i < block.Length; i++)
            {
                if (block[i] == '[')
                    beginnCounter++;
                else if (block[i] == ']')
                {
                    if (beginnCounter == 0)
                        return i;
                    beginnCounter--;
                }
            }
            return -1;
        }

        private readonly Input input;
        private readonly Output output;
    }
Aufruf:
C#:
class Program
    {
        static void Main(string[] args)
        {
            if (args.GetLength(0) > 0)
            {
                if (File.Exists(args[0]))
                {
                    string s = File.ReadAllText(args[0]);

                    Console.WriteLine("Regex Version");
                    Console.WriteLine(string.Empty);

                    BF.Net.BFInterpreter bfi = new BF.Net.BFInterpreter(Input, Output);
                    bfi.Parse(s);

                    Console.WriteLine(string.Empty);
                    Console.WriteLine(string.Empty);
                    Console.WriteLine("Drücken Sie eine Taste zum Beenden des Programmes ...");
                    Console.ReadKey();
                }
            }
        }

        /// <summary>
        /// wird aufgerufen wenn eine Eingabe erwartet wird
        /// </summary>
        public static int Input()
        {
            return (int)Console.ReadKey(false).KeyChar;
        }

        /// <summary>
        /// wird aufgerufen wenn eine Ausgabe erwartet wird
        /// </summary>
        public static void Output(int value)
        {
            Console.Write((char)value);
        }
    }
 

Anhänge

Zuletzt bearbeitet von einem Moderator:

Spyke

Capoeirista
Premium-User
#2
Die zweite Version des Interpreters durchläuft die Zeichenkette in einer Schleife und prüft jedes Zeichen

Der Interpreter
C#:
    internal class BFInterpreter
    {
        /// <summary>
        /// wird aufgerufen wenn eine Eingabe erwartet wird
        /// </summary>
        /// <returns>ASCII Wert des eingegebenen Zeichens</returns>
        public delegate int Input();
        /// <summary>
        /// wird aufgerufen wenn eine Ausgabe erwartet wird
        /// </summary>
        /// <param name="value">ASCII Wert des auszugebenen Zeichens</param>
        public delegate void Output(int value);

        /// <summary>
        /// Objekt wird erstellt
        /// </summary>
        /// <param name="input">Methode für Eingabe</param>
        /// <param name="output">Methode für Ausgabe</param>
        internal BFInterpreter(Input input, Output output)
        {
            this.input = input;
            this.output = output;
        }

        /// <summary>
        /// Interpreter wird gestartet
        /// </summary>
        /// <param name="s">Zeichenkette die untersucht werden soll</param>
        public void Parse2(string s)
        {
            Dictionary<int, int> band = new Dictionary<int, int>();
            int position = 0;

            band.Add(position, 0);

            Parse2(band, ref position, s);
        }

        /// <summary>
        /// analysiert die Zeichenkette
        /// </summary>
        /// <param name="band">Speicher</param>
        /// <param name="position">Position im Speicher</param>
        /// <param name="s">zu untersuchende Zeichenkette</param>
        private void Parse2(Dictionary<int, int> band, ref int position, string s)
        {
            for (int i = 0; i < s.Length; i++)
            {
                switch (s[i])
                {
                    case '+':
                        {
                            band[position]++;
                            if (band[position] > 255)
                                band[position] = 0;
                        } break;
                    case '-':
                        {
                            band[position]--;
                            if (band[position] < 0)
                                band[position] = 255;
                        } break;
                    case '>':
                        {
                            position++;
                            if (!band.ContainsKey(position))
                                band.Add(position, 0);
                        } break;
                    case '<':
                        {
                            position--;
                            if (!band.ContainsKey(position))
                                band.Add(position, 0);
                        } break;
                    case '.':
                        {
                            output(band[position]);
                        } break;
                    case ',':
                        {
                            band[position] = input();
                        } break;
                    case '[':
                        {
                            string block = s.Substring(i + 1);
                            int endBlock = EndBlock(block);
                            if (endBlock > -1)
                            {
                                string block2 = block.Substring(0, endBlock);
                                while (band[position] != 0)
                                    Parse2(band, ref position, block2);
                            }

                            if (endBlock < block.Length) //ist noch nicht das Ende, weiter parsen
                                Parse2(band, ref position, block.Substring(endBlock));

                            s = string.Empty; //Schleife abbrechen
                        } break;
                    default:
                        break;
                }
            }
        }

        /// <summary>
        /// sucht Ende des aktuellen Blockes
        /// </summary>
        private int EndBlock(string block)
        {
            int beginnCounter = 0; //Prüf Variable für innere Blöcke
            for (int i = 0; i < block.Length; i++)
            {
                if (block[i] == '[')
                    beginnCounter++;
                else if (block[i] == ']')
                {
                    if (beginnCounter == 0)
                        return i;
                    beginnCounter--;
                }
            }
            return -1;
        }

        private readonly Input input;
        private readonly Output output;
    }
Aufruf:
C#:
class Program
    {
        static void Main(string[] args)
        {
            if (args.GetLength(0) > 0)
            {
                if (File.Exists(args[0]))
                {
                    string s = File.ReadAllText(args[0]);

                    Console.WriteLine("Schleifen Version");
                    Console.WriteLine(string.Empty);

                    BF.Net.BFInterpreter bfi = new BF.Net.BFInterpreter(Input, Output);
                    bfi.Parse2(s);

                    Console.WriteLine(string.Empty);
                    Console.WriteLine(string.Empty);
                    Console.WriteLine("Drücken Sie eine Taste zum Beenden des Programmes ...");
                    Console.ReadKey();
                }
            }
        }

        /// <summary>
        /// wird aufgerufen wenn eine Eingabe erwartet wird
        /// </summary>
        public static int Input()
        {
            return (int)Console.ReadKey(false).KeyChar;
        }

        /// <summary>
        /// wird aufgerufen wenn eine Ausgabe erwartet wird
        /// </summary>
        public static void Output(int value)
        {
            Console.Write((char)value);
        }
    }
 

Anhänge

Zuletzt bearbeitet von einem Moderator:

Spyke

Capoeirista
Premium-User
#4
Hier nochmals 2 neue Versionen für Regex und Schleife.

Für direkte Text Eingabe wieder BFEditor.exe verwenden oder der BFConsole.exe einen Dateipfad übergeben.

P.S.: Schleifen Version ist schneller
 

Anhänge

Spyke

Capoeirista
Premium-User
#5
Und eine andere Variante
jetzt kann man endlich auch das Textadventure spielen.


Interpreter:
C#:
internal class BFInterpreter
    {
        /// <summary>
        /// wird aufgerufen wenn eine Eingabe erwartet wird
        /// </summary>
        /// <returns>ASCII Wert des eingegebenen Zeichens</returns>
        public delegate int Input();
        /// <summary>
        /// wird aufgerufen wenn eine Ausgabe erwartet wird
        /// </summary>
        /// <param name="value">ASCII Wert des auszugebenen Zeichens</param>
        public delegate void Output(int value);

        /// <summary>
        /// Objekt wird erstellt
        /// </summary>
        /// <param name="input">Methode für Eingabe</param>
        /// <param name="output">Methode für Ausgabe</param>
        internal BFInterpreter(Token token, Input input, Output output)
        {
            this.token = token;
            this.input = input;
            this.output = output;
        }

        public void Start()
        {
            Dictionary<int, int> band = new Dictionary<int, int>();
            band.Add(0, 0);

            int position = 0;

            Analize(token, band, ref position);
        }

        /// <summary>
        /// Analysiert die Token und führt entsprechende Aktionen aus
        /// </summary>
        /// <param name="token">Liste der Token</param>
        /// <param name="band">Speicher</param>
        /// <param name="position">Zeiger</param>
        private void Analize(Token token, Dictionary<int, int> band, ref int position)
        {
            foreach (Token tok in token)
            {
                switch (tok.Typ)
                {
                    case TokenTyp.PointerLeft:
                        {
                            position--;
                            if (!band.ContainsKey(position))
                                band.Add(position, 0);
                        } break;
                    case TokenTyp.PointerRight:
                        {
                            position++;
                            if (!band.ContainsKey(position))
                                band.Add(position, 0);
                        } break;
                    case TokenTyp.Increment:
                        {
                            band[position]++;
                            if (band[position] > 255)
                                band[position] = 0;
                        } break;
                    case TokenTyp.Decrement:
                        {
                            band[position]--;
                            if (band[position] < 0)
                                band[position] = 255;
                        } break;
                    case TokenTyp.Input:
                        {
                            band[position] = input();
                        } break;
                    case TokenTyp.Output:
                        {
                            output(band[position]);
                        } break;
                    case TokenTyp.Block:
                        {
                            while (band[position] != 0)
                                Analize(tok, band, ref position);
                        } break;
                }
            }
        }

        /// <summary>
        /// analysiert die Zeichenkette
        /// </summary>
        /// <param name="s">zu untersuchende Zeichenkette</param>
        public static Token Parse(string s)
        {
            Dictionary<int, Token> tokenBlock = new Dictionary<int, Token>(); //Hilfs Dictionary zum halten der Blockebene
            int blockCounter = 0; //aktuelle Blockebene

            tokenBlock.Add(blockCounter, new Token());

            for (int i = 0; i < s.Length; i++)
            {
                switch (s[i])
                {
                    case '+': tokenBlock[blockCounter].Add(new Token(TokenTyp.Increment)); break;
                    case '-': tokenBlock[blockCounter].Add(new Token(TokenTyp.Decrement)); break;
                    case '>': tokenBlock[blockCounter].Add(new Token(TokenTyp.PointerRight)); break;
                    case '<': tokenBlock[blockCounter].Add(new Token(TokenTyp.PointerLeft)); break;
                    case '.': tokenBlock[blockCounter].Add(new Token(TokenTyp.Output)); break;
                    case ',': tokenBlock[blockCounter].Add(new Token(TokenTyp.Input)); break;
                    case '[':
                        {
                            Token tokBlock = new Token();

                            tokenBlock[blockCounter].Add(tokBlock);
                            tokenBlock.Add(blockCounter + 1, tokBlock);

                            blockCounter++;
                        } break;
                    case ']':
                        {
                            tokenBlock.Remove(blockCounter);
                            blockCounter--;
                        } break;
                    default:
                        break;
                }
            }

            return tokenBlock[0];
        }

        private readonly Token token;
        private readonly Input input;
        private readonly Output output;
    }
C#:
internal class BFInterpreter
    {
        /// <summary>
        /// Tokentypen
        /// </summary>
        public enum TokenTyp
        {
            PointerLeft = 1,
            PointerRight = 2,
            Increment = 3,
            Decrement = 4,
            Input = 5,
            Output = 6,
            Block = 7
        }
    }
C#:
internal class BFInterpreter
    {
        /// <summary>
        /// Klasse zum halten der Token (für Blöcke zum halten ihrer Token)
        /// </summary>
        public class Token : IEnumerable<Token>
        {
            internal Token()
                : this(TokenTyp.Block)
            {
            }

            internal Token(TokenTyp typ)
            {
                this.typ = typ;
                this.token = new List<Token>();
            }

            /// <summary>
            /// Typ
            /// </summary>
            public TokenTyp Typ
            {
                get { return typ; }
            }

            internal void Add(Token tok)
            {
                token.Add(tok);
            }

            #region IEnumerable<Token> Members

            public IEnumerator<Token> GetEnumerator()
            {
                return token.GetEnumerator();
            }

            #endregion

            #region IEnumerable Members

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return token.GetEnumerator();
            }

            #endregion

            private readonly TokenTyp typ;
            private readonly List<Token> token;
        }
    }
Aufruf:
C#:
    class Program
    {
        static void Main(string[] args)
        {
            if (args.GetLength(0) > 0)
            {
                if (File.Exists(args[0]))
                {
                    string s = File.ReadAllText(args[0]);

                    BF.Net.BFInterpreter.Token token = BF.Net.BFInterpreter.Parse(s);

                    BF.Net.BFInterpreter bfi = new BF.Net.BFInterpreter(token, Input, Output);
                    bfi.Start();

                    Console.WriteLine(string.Empty);
                    Console.WriteLine(string.Empty);
                    Console.WriteLine("Drücken Sie eine Taste zum Beenden des Programmes ...");
                    Console.ReadKey();
                }
            }
        }

        /// <summary>
        /// wird aufgerufen wenn eine Eingabe erwartet wird
        /// </summary>
        public static int Input()
        {
            Char chr = Console.ReadKey().KeyChar;
            return (int)chr;
        }

        /// <summary>
        /// wird aufgerufen wenn eine Ausgabe erwartet wird
        /// </summary>
        public static void Output(int value)
        {
            Console.Write((char)value);
        }
    }
 

Anhänge

Zuletzt bearbeitet von einem Moderator:

Neue Beiträge