private static void EvaluateSpiceSharpParser(string expression, int count)
        {
            Console.WriteLine("---------- Spice# Parser ----------");
            var sw = new Stopwatch();

            // Setup
            var parser = new SpiceSharpParser.Parsers.Expression.SpiceExpressionParser();
            var ectxt  = new SpiceExpressionContext(SpiceExpressionMode.LtSpice);
            var pctxt  = new ExpressionParserContext()
            {
                Functions = ectxt.Functions
            };
            var evctxt = new ExpressionEvaluationContext();

            // Parse
            ExpressionParseResult pr = null;

            for (var i = 0; i < 5; i++)
            {
                sw.Restart();
                pr = parser.Parse(expression, pctxt);
                sw.Stop();
                Console.WriteLine($"Parsing (run {i + 1}): {sw.ElapsedTicks} ({sw.ElapsedMilliseconds} ms)");
            }

            // Evaluate a first time
            evctxt.ExpressionContext.Parameters["x"] = new ConstantExpression(1.0);
            Console.WriteLine($"Evaluation: {pr.Value(evctxt)}");

            // Test bulk runs
            sw.Restart();
            for (var i = 0; i < count; i++)
            {
                pr.Value(evctxt);
            }
            sw.Stop();
            Console.WriteLine($"Execution: {sw.ElapsedTicks} ({sw.ElapsedMilliseconds} ms)");
            Console.WriteLine();
        }
Beispiel #2
0
        public static Result Roll(string expression)
        {
            if (string.IsNullOrWhiteSpace(expression))
            {
                throw new DiceRollException("[ERROR]: The roll expression is empty.", expression, 0);
            }

            char[] diceExpression = expression.Trim().ToCharArray();

            for (int i = 0; i < diceExpression.Length; ++i)
            {
                char c = diceExpression[i];
                if (c == 'D')
                {
                    diceExpression[i] = 'd';
                }
            }

            int offset = 0;

            void Panic(string errorMessage)
            {
                throw new DiceRollException(errorMessage, expression, offset);
            }

            char Peek()
            {
                return(diceExpression[offset]);
            }

            char Pop()
            {
                char result = diceExpression[offset];

                ++offset;
                return(result);
            }

            bool EOF()
            {
                return(offset >= diceExpression.Length);
            }

            void GobbleWhitespace()
            {
                while (!EOF() && char.IsWhiteSpace(Peek()))
                {
                    ++offset;
                }
            }

            bool Expect(char c)
            {
                GobbleWhitespace();
                if (diceExpression[offset] == c)
                {
                    ++offset;
                    return(true);
                }
                else
                {
                    return(false);
                }
            }

            int ConsumeNumber()
            {
                int result = 0;

                GobbleWhitespace();
                while (!EOF() && char.IsDigit(Peek()))
                {
                    char c = Pop();
                    int  i = c - '0';
                    result = result * 10 + i;
                }

                return(result);
            }

            int ExpectNonZeroNumber()
            {
                int result = ConsumeNumber();

                if (result <= 0)
                {
                    Panic("Expected a non-zero number.");
                }

                return(result);
            }

            // Can be just [number] or [number]?d[number]
            ExpressionParseResult ConsumeExpression()
            {
                var result = new ExpressionParseResult();

                GobbleWhitespace();
                if (char.IsDigit(Peek()))
                {
                    int number = ConsumeNumber();
                    GobbleWhitespace();

                    if (!EOF() && Peek() == 'd')
                    {
                        ++offset;
                        int number2 = ExpectNonZeroNumber();

                        result.NumDice   = number;
                        result.DiceFaces = number2;
                    }
                    else
                    {
                        result.Constant = number;
                    }
                }
                else if (Expect('d'))
                {
                    int number2 = ExpectNonZeroNumber();

                    result.NumDice   = 1;
                    result.DiceFaces = number2;
                }
                else
                {
                    Panic("Expected dice expression.");
                }

                return(result);
            }

            var rng    = new Random();
            var result = new Result();

            result.Rolls = new Dictionary <string, List <int> >();

            int RollDice(int numFaces)
            {
                int result = 1 + rng.Next(numFaces);

                return(result);
            }

            int sign = 1; // The sign of the "connecting operator"

            // Expressions might start with an '-' or an explicit '+'
            // that we should allow.
            if (Peek() == '-')
            {
                sign = -1;
                ++offset;
            }
            else if (Peek() == '+')
            {
                ++offset;
            }

            do
            {
                var expressionResult = ConsumeExpression();

                if (expressionResult.NumDice > 0)
                {
                    string dieKey  = "d" + expressionResult.DiceFaces;
                    var    results = new List <int>(expressionResult.NumDice);
                    for (int i = 0; i < expressionResult.NumDice; ++i)
                    {
                        int roll = RollDice(expressionResult.DiceFaces);
                        results.Add(roll);
                        result.Total += roll * sign;
                    }

                    if (result.Rolls.ContainsKey(dieKey))
                    {
                        result.Rolls[dieKey].AddRange(results);
                    }
                    else
                    {
                        result.Rolls[dieKey] = results;
                    }
                }
                else
                {
                    result.Modifier += expressionResult.Constant * sign;
                }

                GobbleWhitespace();
                if (!EOF())
                {
                    if (Peek() == '+')
                    {
                        ++offset;
                        sign = 1;
                    }
                    else if (Peek() == '-')
                    {
                        ++offset;
                        sign = -1;
                    }
                    else
                    {
                        // NOTE(istarnion): Panic here if we
                        // don't want to allow chain expressions
                        sign = 1;
                    }
                }
            }while (!EOF());

            result.Total += result.Modifier;

            return(result);
        }