Beispiel #1
0
        /// <summary>
        /// Extracts the individual expression elements, or tokens, from a string
        /// representation of a mathematical expression before they are sent to
        /// the calculation unit for final processing.
        /// </summary>
        /// <returns> A <see cref="System.Collections.Generic.List{DotNetAsm.ExpressionElement}"/>
        /// </returns>
        /// <param name="expression">The mathematical expression.</param>
        public List <ExpressionElement> ParseElements(string expression)
        {
            var               elements       = new List <ExpressionElement>();
            StringBuilder     elementBuilder = new StringBuilder();
            ExpressionElement currentElement = new ExpressionElement();

            for (int i = 0; i < expression.Length; i++)
            {
                var c = expression[i];
                if (char.IsWhiteSpace(c))
                {
                    AddElement();
                }
                else if (c.IsOperator() || c == ',')
                {
                    char next          = i < expression.Length - 1 ? expression[i + 1] : char.MinValue;
                    bool nextIsOperand = char.IsLetterOrDigit(next) || next == '_' || next == '.' || next == '#';
                    if (currentElement.type != ExpressionElement.Type.Operator)
                    {
                        AddElement();
                        currentElement.type = ExpressionElement.Type.Operator;
                        if (c == ',')
                        {
                            currentElement.subType = ExpressionElement.Subtype.Binary;
                        }
                        else
                        {
                            if (currentElement.subType == ExpressionElement.Subtype.Open)
                            {
                                if (c.IsRadixOperator() && nextIsOperand)
                                {
                                    currentElement.type    = ExpressionElement.Type.Operand;
                                    currentElement.subType = ExpressionElement.Subtype.None;
                                }
                                else
                                {
                                    currentElement.subType = ExpressionElement.Subtype.Unary;
                                }
                            }
                            else
                            {
                                currentElement.subType = ExpressionElement.Subtype.Binary;
                            }
                        }
                    }
                    else if (!_compounds.Contains(elementBuilder.ToString() + c))
                    {
                        currentElement.subType = ExpressionElement.Subtype.Binary;
                        AddElement();
                        if (c.IsRadixOperator())
                        {
                            currentElement.type    = ExpressionElement.Type.Operand;
                            currentElement.subType = ExpressionElement.Subtype.None;
                        }
                        else
                        {
                            currentElement.subType = ExpressionElement.Subtype.Unary;
                        }
                    }
                    elementBuilder.Append(c);
                }
                else if (c == '(' || c == ')')
                {
                    AddElement();
                    if (c == '(' && elements.Count > 0 && (currentElement.type == ExpressionElement.Type.Operand && char.IsLetter(currentElement.word[0])))
                    {
                        // Convert operand expressions to functions where appropriate
                        elementBuilder.Append(elements.Last().word);
                        currentElement.type = ExpressionElement.Type.Function;
                        elements.RemoveAt(elements.Count - 1);
                        AddElement();
                    }
                    currentElement.type = ExpressionElement.Type.Group;
                    if (c == '(')
                    {
                        currentElement.subType = ExpressionElement.Subtype.Open;
                    }
                    else
                    {
                        currentElement.subType = ExpressionElement.Subtype.Close;
                    }
                    elementBuilder.Append(c);
                }
                else
                {
                    if (currentElement.type != ExpressionElement.Type.Operand)
                    {
                        AddElement();
                        currentElement.type    = ExpressionElement.Type.Operand;
                        currentElement.subType = ExpressionElement.Subtype.None;
                    }
                    elementBuilder.Append(c);
                }
                if (i == expression.Length - 1)
                {
                    AddElement();
                }
            }
            return(elements);

            void AddElement()
            {
                if (elementBuilder.Length > 0)
                {
                    currentElement.word = elementBuilder.ToString();
                    elementBuilder.Clear();
                    elements.Add(currentElement);
                }
            }
        }
Beispiel #2
0
        double Calculate(List <ExpressionElement> parsedElements)
        {
            var            operators  = new Stack <ExpressionElement>();
            Stack <double> result     = new Stack <double>();
            int            openParens = 0;

            for (int i = 0; i < parsedElements.Count; i++)
            {
                var element = parsedElements[i];
                if (openParens > 0)
                {
                    int parmsPassed = 1;
                    int start = i + 1, len = 0;
                    for (i++; i < parsedElements.Count && openParens > 0; i++)
                    {
                        element = parsedElements[i];
                        if (element.word.Equals(",") && openParens < 2)
                        {
                            if (len == 0)
                            {
                                throw new Exception(); // we did a f(,n) thing
                            }
                            result.Push(Calculate(parsedElements.GetRange(start, len)));
                            parmsPassed++;
                            start = i + 1;
                            len   = 0;
                        }
                        else
                        {
                            if (element.subType == ExpressionElement.Subtype.Open)
                            {
                                openParens++;
                            }
                            else if (element.subType == ExpressionElement.Subtype.Close)
                            {
                                openParens--;
                            }
                            if (openParens > 0)
                            {
                                len++;
                            }
                        }
                    }
                    if (len == 0)
                    {
                        throw new Exception(); // we did a f()/f(n,) thing
                    }
                    i--;
                    result.Push(Calculate(parsedElements.GetRange(start, len)));
                    result.Push(parmsPassed);
                }
                else if (element.type == ExpressionElement.Type.Operand)
                {
                    if (element.word[0].IsRadixOperator())
                    {
                        var hexbin = element.word.Substring(1);
                        int radix;
                        if (element.word[0] == '%')
                        {
                            radix  = 2;
                            hexbin = Regex.Replace(hexbin, @"^([#.]+)$", m => m.Groups[1].Value.Replace("#", "1").Replace(".", "0"));
                        }
                        else
                        {
                            radix = 16;
                        }
                        result.Push(Convert.ToInt64(hexbin, radix));
                    }
                    else
                    {
                        result.Push(double.Parse(element.word));
                    }
                }
                else if (element.type == ExpressionElement.Type.Function || element.subType == ExpressionElement.Subtype.Open)
                {
                    operators.Push(element);
                    if (element.type == ExpressionElement.Type.Function)
                    {
                        openParens = 1;
                    }
                    else if (openParens > 0)
                    {
                        openParens++; // we're in a function track opening parens
                    }
                }
                else if (element.type == ExpressionElement.Type.Operator)
                {
                    if (operators.Count > 0)
                    {
                        ExpressionElement topElement = new ExpressionElement();
                        var elemOrder = _operators[element].Item2;
                        topElement = operators.Peek();
                        while (topElement.type == ExpressionElement.Type.Function || topElement.type == ExpressionElement.Type.Operator || topElement.subType == ExpressionElement.Subtype.Open)
                        {
                            var topOrder = topElement.type == ExpressionElement.Type.Operator ? _operators[topElement].Item2 : int.MaxValue;
                            if (topElement.subType != ExpressionElement.Subtype.Open && topOrder >= elemOrder)
                            {
                                operators.Pop();
                                DoOperation(topElement);
                                if (operators.Count > 0)
                                {
                                    topElement = operators.Peek();
                                }
                                else
                                {
                                    break;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    operators.Push(element);
                }
                else if (element.subType == ExpressionElement.Subtype.Close)
                {
                    if (operators.Count > 0)
                    {
                        var topElement = operators.Peek();
                        while (topElement.subType != ExpressionElement.Subtype.Open)
                        {
                            operators.Pop();
                            DoOperation(topElement);
                            if (operators.Count == 0)
                            {
                                throw new Exception();
                            }
                            topElement = operators.Peek();
                        }
                        if (topElement.subType == ExpressionElement.Subtype.Open)
                        {
                            operators.Pop();
                        }
                    }
                }
            }
            if (openParens > 0)
            {
                throw new Exception();
            }
            while (operators.Count > 0)
            {
                DoOperation(operators.Pop());
            }

            void DoOperation(ExpressionElement op)
            {
                OperationDef  operation = null;
                List <double> parms     = new List <double> {
                    result.Pop()
                };

                if (op.type == ExpressionElement.Type.Function)
                {
                    operation = _functions[op.word];
                    var parmcount = operation.Item2;
                    if (parmcount != (int)parms.Last())
                    {
                        throw new Exception(); // parms passed does not match function's definition
                    }
                    parms.Clear();
                    while (parmcount-- > 0)
                    {
                        parms.Add(result.Pop());
                    }
                }
                else
                {
                    operation = _operators[op];
                    if (op.subType == ExpressionElement.Subtype.Binary)
                    {
                        parms.Add(result.Pop());
                    }
                    if (op.arithmeticType == ExpressionElement.ArithmeticType.Boolean &&
                        parms.Any(p => !(p.AlmostEquals(1) || p.AlmostEquals(0))))
                    {
                        throw new Exception();
                    }
                    if (op.arithmeticType == ExpressionElement.ArithmeticType.Integral &&
                        parms.Any(p => !p.AlmostEquals(Math.Round(p))))
                    {
                        throw new Exception();
                    }
                }
                result.Push(operation.Item1(parms));
            }

            if (result.Count > 1)
            {
                throw new Exception();
            }
            return(result.Pop());
        }
Beispiel #3
0
        /// <summary>
        /// Translates all special symbols in the expression into a
        /// <see cref="System.Collections.Generic.List{DotNetAsm.ExpressionElement}"/>
        /// for use by the evualator.
        /// </summary>
        /// <returns>The expression symbols.</returns>
        /// <param name="line">The current source line.</param>
        /// <param name="expression">The expression to evaluate.</param>
        /// <param name="scope">The current scope.</param>
        /// <param name="errorOnNotFound">If set to <c>true</c> raise an error
        /// if a symbol encountered in the expression was not found.</param>
        public List <ExpressionElement> TranslateExpressionSymbols(SourceLine line, string expression, string scope, bool errorOnNotFound)
        {
            char          lastTokenChar = char.MinValue;
            StringBuilder translated = new StringBuilder(), symbolBuilder = new StringBuilder();

            for (int i = 0; i < expression.Length; i++)
            {
                char c = expression[i];
                if (c == '\'' || c == '"')
                {
                    var literal   = expression.GetNextQuotedString(i);
                    var unescaped = literal.TrimOnce(c);
                    if (unescaped.Contains("\\"))
                    {
                        unescaped = Regex.Unescape(unescaped);
                    }
                    var bytes = Assembler.Encoding.GetBytes(unescaped);
                    if (bytes.Length > sizeof(int))
                    {
                        throw new OverflowException(literal);
                    }
                    if (bytes.Length < sizeof(int))
                    {
                        Array.Resize(ref bytes, sizeof(int));
                    }
                    var encodedValue = BitConverter.ToInt32(bytes, 0);
                    translated.Append(encodedValue);
                    i            += literal.Length - 1;
                    lastTokenChar = '0'; // can be any operand
                }
                else if ((c == '*' || c == '-' || c == '+') &&
                         (lastTokenChar.IsOperator() || lastTokenChar == '(' || lastTokenChar == char.MinValue))
                {
                    bool isSpecial = false;
                    if (c == '*' && (lastTokenChar == '(' || i == 0 || expression[i - 1] != '*'))
                    {
                        isSpecial = true;
                        translated.Append(Assembler.Output.LogicalPC.ToString());
                    }
                    else if (lastTokenChar == '(' ||
                             lastTokenChar == char.MinValue || (lastTokenChar.IsOperator()) && char.IsWhiteSpace(expression[i - 1]))
                    {
                        int j = i, k;
                        for (; j < expression.Length && expression[j] == c; j++)
                        {
                            symbolBuilder.Append(c);
                        }
                        for (k = j; k < expression.Length && char.IsWhiteSpace(expression[k]); k++)
                        {
                        }
                        if (j >= expression.Length ||
                            (lastTokenChar == '(' && expression[k] == ')') ||
                            ((lastTokenChar == char.MinValue || lastTokenChar.IsOperator()) &&
                             char.IsWhiteSpace(expression[k - 1]) && expression[k].IsOperator()))
                        {
                            isSpecial = true;
                            translated.Append(ConvertAnonymous(symbolBuilder.ToString(), line, errorOnNotFound));
                            i = j - 1;
                        }
                        symbolBuilder.Clear();
                    }
                    if (isSpecial)
                    {
                        lastTokenChar = translated[translated.Length - 1];
                    }
                    else
                    {
                        lastTokenChar = c;
                        translated.Append(c);
                    }
                }
                else
                {
                    if (!char.IsWhiteSpace(c))
                    {
                        lastTokenChar = c;
                    }
                    translated.Append(c);
                }
            }
            var elements = Assembler.Evaluator.ParseElements(translated.ToString()).ToList();

            for (int i = 0; i < elements.Count; i++)
            {
                if (elements[i].type == ExpressionElement.Type.Operand && (elements[i].word[0] == '_' || char.IsLetter(elements[i].word[0])))
                {
                    var symbol = elements[i].word;
                    if (_constants.ContainsKey(symbol))
                    {
                        symbol = _constants[symbol].ToString();
                    }
                    else
                    {
                        symbol = GetNamedSymbolValue(symbol, line, scope);
                    }
                    if (symbol[0] == '-')
                    {
                        elements.Insert(i, new ExpressionElement
                        {
                            word    = "-",
                            type    = ExpressionElement.Type.Operator,
                            subType = ExpressionElement.Subtype.Unary
                        });
                        i++;
                        symbol = symbol.Substring(1);
                    }
                    elements[i] = new ExpressionElement
                    {
                        word    = symbol,
                        type    = ExpressionElement.Type.Operand,
                        subType = ExpressionElement.Subtype.None
                    };
                }
            }
            return(elements);
        }