具有讽刺意味的是,使用自己的语言的编译器问题

Irony compiler problems with own language

提问人:MrSticks 提问时间:9/4/2023 更新时间:9/4/2023 访问量:26

问:

我使用 Irony.Compiler.Grammar 类来编译我自己的代码。 解析正在工作,但语法的初始化需要 4 秒才能加载到我的 unity-web 项目中,这是为了占用时间。我不完全理解解析,还有一些需要改进的地方。我为您提供编码。请让我知道出了什么问题以及您需要什么来帮助我。 谢谢

下面是编码语法的示例

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()

现在是我的语法代码

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;
        }
    }
}

现在解析一些部分

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;
    }

我设法运行了代码,但我需要改进它,因此初始化不需要 4 秒即可加载。我认为语法是这里的问题。

C# unity-game-engine 解析 讽刺

评论


答: 暂无答案