3

I have this code that generates tokens in string form based on what is matched with Regex:

public static List<Tuple<string, string>> GetTokens(string input)
    {
        List<Tuple<string, string>> ret = new List<Tuple<string, string>>();
        Regex r = new Regex("(?<Comma>\\,)" +
            "|(?<Dot>\\.)" +
            "|(?<SemiColon>\\;)" +
            "|(?<DoubleDot>\\:)" +
            "|(?<Increment>\\+\\+)" +
            "|(?<greater>\\>)" +
            "|(?<smaller>\\<)" +
            "|(?<Decrement>\\-\\-)" +
            "|(?<SystemCommand> *deviceListCount *| *deviceList *| *devices *| *device *| *str *| *int *| *dev *| *bool *| *print *| *wait *| *device *| *if *| *while *| *loop *)" +
            "|(?<OpenBracket>\\()" +
            "|(?<CloseBracket>\\))" +                
            "|(?<DeviceCommand> *On *| *Off *| *Open *| *Close *| *Move *| *Detect *)" +
            "|(?<Integer>\\d+)"+
            "|(?<equals> *[=] *)" +                
            "|(?<String>[aA-zZ0-9 ]*)");
        foreach (Match item in r.Matches(input))
        {
            for (int i = 1; i < item.Groups.Count; i++)
            {
                string v = item.Groups[i].Value;
                if (v != "")
                {
                    ret.Add(new Tuple<string, string>(r.GroupNameFromNumber(i), v));
                }
            }
        }
        return ret;
    }

To start off simple, how can I use the method above to create a print command:

print(hello world)

I want to run the code with something like this:

RunCode(GetTokens("print(Hello World)"))

This code should produce the same effect as:

Console.WriteLine("Hello World");
yacc
  • 2,915
  • 4
  • 19
  • 33
  • You are creating your own language. Congratulations! Indentation is one of the rather complex feature of language implementation. If you are right now working with the basics, i recommend deferring nested structures like while loop, and practice the basics first. – inquisitive Apr 22 '20 at 02:23
  • yes, I agree completely, that's why I want to start off with the 'print(hello world)' command for now it seems the most basic of all the commands at the moment, the rest was just extra to be honest. – TyperMan1133 Apr 22 '20 at 02:26
  • 2
    A regex can so only very simple constructs. If you understand that regex you have posted above, i would say you are good with it. To implement a parser in true sence, you need to learn about EBNF grammars. They are on the similar oines to regexes, but more powerful. For examlle [here](https://parrot.github.io/parrot-docs0/0.4.11/html/languages/lua/doc/lua51.bnf.html) is that for a very simple language called Lua. – inquisitive Apr 22 '20 at 02:27
  • 1
    Also can you please tell us why you are taking this journey? Is this purely for education and hobby or do you need it for professional purpose? If hobby/education then welcome. If for practical use in job then you better use some ready made stuff out their. This path will take you on a journey of a couple of months before you get something practically working. Sorry for disappointing. But parser generation is one of the most notorious aspects of computer world. – inquisitive Apr 22 '20 at 02:31
  • 1
    I am an aspiring game developer as well as a Software Developer student (2nd year), I started using unity about 6 months ago and recently played a game called "Else Heart.Break()" that really got me interested in making a hacking game where you sneak around an open world and hack various systems/devices to gain access to places and so on, – TyperMan1133 Apr 22 '20 at 02:41
  • 1
    I tried implementing a custom in-game interpreter using only Regex with very basic commands, but I got really into compilers/Interpreters and how to really make a dynamic and easy to use language for a game and many for real world use, and I saw a few documents and articles about Lexers and Abstract tree Parsers but I'm failing to get a good grip on how it all interacts together and how to properly implement it. sorry for double comment, there wasn't enough characters left in the first half. – TyperMan1133 Apr 22 '20 at 02:41
  • 1
    you could have a look into lex&yacc, https://stackoverflow.com/questions/540593/lex-yacc-for-c – yacc Apr 23 '20 at 06:52
  • I am aware of Yacc, I am keener on ways to implement it from scratch, to be honest, but if I struggle too much I think I might use your suggestion as well as @inquisitive's suggestion of learning EBNF grammars. – TyperMan1133 Apr 23 '20 at 13:03
  • 1
    Crafting your own interpreter is not trivial (and too broad a topic for a SO question), as you can see by reading dedicated literature like: http://craftinginterpreters.com/contents.html . Personally I'd also suggest using a parser generator like YACC or ANTLR – UnholySheep Apr 23 '20 at 15:07
  • 1
    Thank you everyone for the help, I appreciate it very much. – TyperMan1133 Apr 23 '20 at 15:17

1 Answers1

0

Edit Update! I think i found a way to do it. I created a way of doing it using the 2 methods below: Firstly this method that seeks and returns nested string for use in loops/while loops and if statments:

public static string UntilNestedEnd(List<Tuple<string, string>> t, ref int i)
        {            
            string inner = "";
            int nested = 0;
            while (true)
            {
                if (i < t.Count-1)
                {
                    i++;
                    if (t[i].Item2 == ")")
                    {
                        nested--;
                        if (nested > 0)
                        {
                            inner += t[i].Item2;
                        }
                    }
                    else if (t[i].Item2 == "(")
                    {
                        if (nested > 0)
                        {
                            inner += t[i].Item2;
                        }
                        nested++;
                    }
                    else
                    {
                        inner += t[i].Item2;
                    }
                    if (nested == 0)
                    {
                        break;
                    }                    
                }
            }
            return inner;
        }

Here is the code that can execute the commands, all i have to do is say how many steps it should skip ahead before retrieving the string and it resulted in nested statements that seem to work, so far i only have 2 commands at the moment 'print' and 'loop':

public static void RunCode(string input)
        {
            var g = GetTokens(input);
            for (int i = 0; i < g.Count; i++)
            {
                if (g[i].Item2 == "print")
                {
                    Console.WriteLine(UntilNestedEnd(g, ref i));
                }
                else if (g[i].Item2 == "loop")
                {
                    int cnt = int.Parse(g[i+2].Item2);
                    i +=2;
                    string nested = UntilNestedEnd(g,ref i);                    
                    for (int x = 0; x < cnt; x++)
                    {
                        RunCode(nested);
                    }
                }
            }
        }

Here is the code that runs it:

static void Main(string[] args)
        {
            RunCode("loop:2(loop:2(loop:2(print(hello))))");
            Console.ReadLine();
        }