Irony compiler problems with own language

36 views Asked by At

i use the Irony.Compiler.Grammar Class to compile my own code. the parsing is working but the init of the grammar takes 4 seconds to load in my unity-web project and thats to mutch time. I dont fully understand the parsing and there are some things to improve. i provide you with the coding. please let me know whats wrong and what you need to help me. thanks

Here is an example of the coding syntax

SET(OX, "BONE.PATH")
PRINT(GET(OX,"BONE.PATH"))
SET(OY, "BONE.PATH",GET(OX,"BONE.PATH")+1)
WAIT(5000)
IF(GETVAR("X") < 100)
PRINT("IN IF")
ENDIF()

now the code of my grammar

public class ExpressionGrammar : Irony.Compiler.Grammar
{
    public ExpressionGrammar()
    {
        string[] actionArray = GetActionKeys();

        // 1. Terminals
        Terminal number = new NumberTerminal("number");

        IdentifierTerminal var = new ("string", actionArray);
        var.AddReservedWords(actionArray);
        Terminal stringTerm = var;

        NonTerminal _string = new ("_string");
        NonTerminal stringOp = new ("stringOp");
        StringLiteral stringLiteral = new ("string_Literal1");
        StringLiteral stringLiteral2 = new ("string_Literal2", "\"\"\"", "\"\"\"");
        StringLiteral stringLiteral3 = new ("string_Literal3", "'", "'");
        StringLiteral stringLiteral4 = new ("string_Literal4", "'''", "'''");

        Terminal Comment = new CommentTerminal("Comment", "#", "", "");
        ExtraTerminals.Add(Comment);

        // 2. Non-terminals
        NonTerminal ExprLine = new ("ExprLine");

        NonTerminal BinaryOp = new ("BinOp");
        NonTerminal DefaultExpression = new ("Expression");
        NonTerminal Calculation = new ("Calculation");

        NonTerminal FunctionName = new ("FunctionName");
        NonTerminal Function = new ("Function");

        NonTerminal CompareOp = new ("CompareOperator");
        NonTerminal Compare = new ("Compare");

        NonTerminal andOp = new ("ANDOP");
        NonTerminal And = new ("AND");
        NonTerminal AndExpression = new ("AndExpression"); // New non-terminal for multiple && statements

        NonTerminal orOp = new ("OROP");
        NonTerminal Or = new ("OR");
        NonTerminal OrExpression = new ("OrExpression"); // New non-terminal for multiple && statements

        NonTerminal elementPath = new ("PATH");

        NonTerminal variable = new ("Variable");
        NonTerminal DynamicVariable = new ("DynamicVariable");
        NonTerminal DynamicVariableOp = new ("DynamicVariableOp");
        NonTerminal varOp = new ("varop");

        // 3. BNF rules
        //all functions
        GetExpressionFromArray(FunctionName, actionArray);

        DefaultExpression.Expression =
            number | elementPath | Function | Compare | And | Or | variable | _string | DynamicVariable |
             Calculation;

        Calculation.Expression = DefaultExpression + BinaryOp + DefaultExpression | BinaryOp + DefaultExpression;

        Compare.Expression = DefaultExpression + CompareOp + DefaultExpression;

        AndExpression.Expression =
        DefaultExpression + andOp + AndExpression |
        DefaultExpression + andOp + DefaultExpression;

        And.Expression = AndExpression | DefaultExpression + andOp + DefaultExpression;

        OrExpression.Expression =
        DefaultExpression + orOp + OrExpression |
        DefaultExpression + orOp + DefaultExpression;

        Or.Expression = OrExpression | DefaultExpression + orOp + DefaultExpression;

        Function.Expression =// FunctionName;
            FunctionName |
            FunctionName + _string |
            FunctionName + DefaultExpression |
            //7 parameters (A;B;C;D;E;F;G)
            FunctionName + "(" + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + ")" |
            //6 parameters (A;B;C;D;E;F)
            FunctionName + "(" + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + ")" |
            //5 parameters (A;B;C;D;E)
            FunctionName + "(" + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + ")" |
            //4 parameters (A;B;C;D)
            FunctionName + "(" + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + ")" |
            //3 parameters (A;B;C)
            FunctionName + "(" + DefaultExpression + "," + DefaultExpression + "," + DefaultExpression + ")" |
            //2 parameters (A;B)
            FunctionName + "(" + DefaultExpression + "," + DefaultExpression + ")" |
            //1 parameter (A)
            FunctionName + "(" + DefaultExpression + ")" | "(" + ")" | "(" + Compare + ")" | "(" + Calculation + ")" | "(" + Function + ")";
        
        variable.Expression = varOp + _string;
        varOp.Expression = "$";
        DynamicVariable.Expression = DynamicVariableOp + number + DynamicVariableOp;
        DynamicVariableOp.Expression = Symbol("{") | "}";

        _string.Expression = stringTerm | stringLiteral | stringLiteral2 | stringLiteral3 | stringLiteral4;
        stringOp.Expression = "\"";

        BinaryOp.Expression =
            Symbol("+") | "-" | "*" | "/" | "**";

        CompareOp.Expression =
            Symbol("==") | ">=" | "<=" | "<" | ">" | "!=";

        andOp.Expression =
            Symbol("&&") | "AND";

        orOp.Expression =
            Symbol("||") | "OR";

        elementPath.Expression =
            _string + "." + _string |
            _string + "." + _string + "." + _string |
            _string + "." + _string + "." + _string + "." + _string;


        ExprLine.Expression = DefaultExpression + Eof; //Eof is a predefined EOF terminal

        this.Root = ExprLine;             //Set grammar top element

        // 4. Set operators precedence and associativity
        RegisterOperators(1, "+", "-");
        RegisterOperators(2, "*", "/");
        RegisterOperators(3, Associativity.Right, "**");
        RegisterOperators(4, "&&", "AND");
        RegisterOperators(5, "||", "OR");
        RegisterOperators(6, actionArray);

        // 5. Register parenthesis as punctuation symbols
        //    so they will not appear in the syntax tree
        PunctuationSymbols.AddRange(new string[] { "(", ")", "&&", "||", "AND", "OR", ",", "()", "$", "\"", "{", "}" });

    }
    private string[] GetActionKeys()
    {
        //Contains GET, SET, PRINT, IF, ENDIF, WAIT etc
        string[] keys = ActionManager.Instance.actionCollection.Select(x => x.Key.ToString()).ToArray();
        return keys;
    }

    private void GetExpressionFromArray(NonTerminal expression, string[] commandArray)
    {
        foreach (string command in commandArray)
        {
            if (expression.Expression == null)
                expression.Expression = command;
            else
                expression.Expression |= command;
        }
    }
}

now some of the parsing parts

private static string CompileNode(MyNode rootNode, Config config, string comandName, bool runFunctions)
    {
        string returnValue = "";
        if (rootNode.Tag != null)
        {
            string tagName = rootNode.Tag.Element.Name;
            List<MyNode> parameters = rootNode.childNodes;
            //print("TAG:" + tagName);
            switch (tagName)
            {
                case "Function":
                    foreach (MyNode param in parameters)
                    {
                        //print("param:"+param);
                        if (!param.Tag.Element.Name.ToUpper().StartsWith("STRING") && !param.Tag.Element.Name.ToUpper().StartsWith("RESERVEDWORD"))
                        {
                            returnValue = CompileNode(param, config, comandName, runFunctions);
                        }
                    }
                    returnValue = StartFunction(parameters, config, comandName, runFunctions);
                    rootNode.name = returnValue;
                    break;
                case "Calculation":
                    string number1Type = "";
                    string number2Type = "";

                    string number1 = "0";
                    string number2 = "0";

                    string _operator = "";
                    ///if 3 parameters (10 - 10)
                    if (parameters.Count > 2)
                    {
                        ///Get number1
                        number1Type = parameters[0].Tag.Element.Name.ToUpper();

                        if (!number1Type.Equals("NUMBER"))
                            returnValue = CompileNode(parameters[0], config, comandName, runFunctions);
                        number1 = parameters[0].name;

                        ///get operator
                        _operator = parameters[1].name;

                        ///get number2 (check if number two is empty; forexample [-1000] has no number2 )
                        number2Type = parameters[2].Tag.Element.Name.ToUpper();
                        if (!number2Type.Equals("NUMBER"))
                            returnValue = CompileNode(parameters[2], config, comandName, runFunctions);
                        number2 = parameters[2].name;

                    }
                    ///if 2 parameters (- 10)
                    else
                    {
                        ///Get number1
                        number1Type = parameters[1].Tag.Element.Name.ToUpper();

                        if (!number1Type.Equals("NUMBER"))
                            returnValue = CompileNode(parameters[1], config, comandName, runFunctions);
                        number2 = parameters[1].name;

                        ///get operator
                        _operator = parameters[0].name;

                        number1 = "0";
                    }
                    rootNode.name = Calculate(number1, _operator, number2);
                    break;
                case "Compare":
                    string number1Type2 = parameters[0].Tag.Element.Name.ToUpper();
                    string _operator2 = parameters[1].name;
                    string number2Type2 = parameters[2].Tag.Element.Name.ToUpper();

                    if (!number1Type2.Equals("NUMBER") && !number1Type2.Equals("STRING"))
                        returnValue = CompileNode(parameters[0], config, comandName, runFunctions);
                    if (!number2Type2.Equals("NUMBER") && !number2Type2.Equals("STRING"))
                        returnValue = CompileNode(parameters[2], config, comandName, runFunctions);
                    rootNode.name = Compare(parameters[0].name, _operator2, parameters[2].name);
                    break;
                case "AND":
                    string number1Type3 = parameters[0].Tag.Element.Name.ToUpper();
                    string number2Type3 = parameters[1].Tag.Element.Name.ToUpper();
                    if (!number1Type3.Equals("STRING"))
                        returnValue = CompileNode(parameters[0], config, comandName, runFunctions);
                    if (!number2Type3.Equals("STRING"))
                        returnValue = CompileNode(parameters[1], config, comandName, runFunctions);
                    rootNode.name = AND(parameters[0].name, parameters[1].name);
                    break;
                case "OR":
                    string number1Type4 = parameters[0].Tag.Element.Name.ToUpper();
                    string number2Type4 = parameters[1].Tag.Element.Name.ToUpper();
                    if (!number1Type4.Equals("STRING"))
                        returnValue = CompileNode(parameters[0], config, comandName, runFunctions);
                    if (!number2Type4.Equals("STRING"))
                        returnValue = CompileNode(parameters[1], config, comandName, runFunctions);
                    rootNode.name = OR(parameters[0].name, parameters[1].name);
                    break;
                default:
                    if (rootNode != null && rootNode.childNodes != null)
                        foreach (MyNode child in rootNode.childNodes)
                        {
                            returnValue = CompileNode(child, config, comandName, runFunctions);
                        };
                    break;
            }
        }
        else
        {
            foreach (MyNode child in rootNode.childNodes)
            {
                returnValue = CompileNode(child, config, comandName, runFunctions);
            }
        }
        // print("retVal:"+returnValue+"  rootnode:"+rootNode.name);
        return returnValue;
    }

i managed to get the code running but i need to improve it, so the initialisation dont takes 4 seconds to load. i think the grammar is the problem here.

0

There are 0 answers