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.