Skip to main content
deleted 88 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Please help me find the bottleneck in my code Scripting language parser

I'm making a scripting language parser and it's shaping up well but it takes is about 30ms to do 30 or so odd/even checks. Profiler

Profiler tells me that it's taking most of the time in the InvokeOperator.OperateInvokeOperator.Operate function but that doesn't tell me a lot because the Operate call the Run method on the CodeBlockCodeBlock which in turn again calls the Operate call and makes it very hard to actually determine what's taking as long.

I don't know if you guys do full project reviews like this but I would appreciate it a lot.

Here's the Github repo https://github.com/LukaHorvat/KentoGithub repo

Here are the most important bits of the code:

Stack<Token> solvingStack = new Stack<Token>();
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..codeblock. A

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 CodeBlockCodeBlock, 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.

Please help me find the bottleneck in my code

I'm making a scripting language parser and it's shaping up well but it takes is about 30ms to do 30 or so odd/even checks. 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.

I don't know if you guys do full project reviews like this but I would appreciate it a lot.

Here's the Github repo https://github.com/LukaHorvat/Kento

Here are the most important bits of the code:

Stack<Token> solvingStack = new Stack<Token>();
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.

Scripting language parser

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.

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<Token> solvingStack = new Stack<Token>();
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.

changed format so that scrollbars don't appear
Source Link
Michael K
  • 2.9k
  • 1
  • 22
  • 24
        Stack<Token> solvingStack = new Stack<Token>();
        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();
        Stack<Token> solvingStack = new Stack<Token>();
        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();
Stack<Token> solvingStack = new Stack<Token>();
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();
added 1425 characters in body
Source Link
Darwin
  • 376
  • 1
  • 6

Here are the most important bits of the code:

        Stack<Token> solvingStack = new Stack<Token>();
        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.

Here are the most important bits of the code:

        Stack<Token> solvingStack = new Stack<Token>();
        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.

Tweeted twitter.com/#!/StackCodeReview/status/52293720334278656
Source Link
Darwin
  • 376
  • 1
  • 6
Loading