patterncsharpMinor
Scripting language parser
Viewed 0 times
parserscriptinglanguage
Problem
I'm making a scripting language parser and it's shaping up well but it takes about 30ms to do 30 or so odd/even checks.
Here's the Github repo
Here are the most important bits of the code:
It's how the code is parsed after the infix expression is turned into RPN.
A token can be an operator or a value and a value can be a literal, identifier,
A somewhat special case is a function because it's not parsed to RPN directly but only the code inside of it is. Then is there's an invoke operator, it takes the array of arguments that was provided and the function before it and runs the function (which inherits from
What each operator does on different types of values is determined by the operator itself in the Operators.cs file.
Profiler tells me that it's taking most of the time in the InvokeOperator.Operate function but that doesn't tell me a lot because the Operate call the Run method on the CodeBlock which in turn again calls the Operate call and makes it very hard to actually determine what's taking as long.Here's the Github repo
Here are the most important bits of the code:
Stack solvingStack = new Stack();
for ( int i = 0 ; i < value.Count ; ++i )
{
if ( value[ i ] is Operator )
{
Operator op = (Operator)value[ i ];
if ( op.Type == OperatorType.PrefixUnary || op.Type == OperatorType.SufixUnary )
{
op.Operate( ( solvingStack.Pop() as Value ), new NoValue() );
} else
{
Value second = (Value)solvingStack.Pop();
Value result = op.Operate( ( solvingStack.Pop() as Value ), second );
solvingStack.Push( result );
}
} else
{
solvingStack.Push( value[ i ] );
}
}
Compiler.ExitScope();
if ( solvingStack.Count == 0 ) return new NoValue();
else return (Value)solvingStack.Peek();It's how the code is parsed after the infix expression is turned into RPN.
A token can be an operator or a value and a value can be a literal, identifier,
codeblock.A somewhat special case is a function because it's not parsed to RPN directly but only the code inside of it is. Then is there's an invoke operator, it takes the array of arguments that was provided and the function before it and runs the function (which inherits from
CodeBlock, so it also runs the same thing that is shown here).What each operator does on different types of values is determined by the operator itself in the Operators.cs file.
Solution
I am not sure if these are bottlenecks, but they are at least performance improvements.
-
Replace
-
You can replace
with
to have only one typecheck (
-
You can replace
with
to eliminate the index operations
-
Replace
Stack with Stack since you are only pushing/popping Value. This way there is no need to do expensive casts.-
You can replace
if ( value[ i ] is Operator )
{
Operator op = (Operator)value[ i ];with
Operator op = value[ i ] as Operator;
if ( op != null ) // it was an Operatorto have only one typecheck (
x as y) instead of two (x is y and (y) x).-
You can replace
for ( int i = 0 ; i < value.Count ; ++i )with
foreach(Token item in value)to eliminate the index operations
value[ i ].Code Snippets
if ( value[ i ] is Operator )
{
Operator op = (Operator)value[ i ];Operator op = value[ i ] as Operator;
if ( op != null ) // it was an Operatorfor ( int i = 0 ; i < value.Count ; ++i )foreach(Token item in value)Context
StackExchange Code Review Q#1495, answer score: 3
Revisions (0)
No revisions yet.