提问人:MrSticks 提问时间:9/4/2023 更新时间:9/4/2023 访问量:26
具有讽刺意味的是,使用自己的语言的编译器问题
Irony compiler problems with own language
问:
我使用 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 秒即可加载。我认为语法是这里的问题。
答: 暂无答案
评论