/// <summary> /// <para>Compiles a new <see cref="IntermediateExpression"/> from a source <see cref="ExpressionSyntax"/>.</para> /// </summary> /// <param name="syntax">The parsed string that describes an expression to compile.</param> /// <param name="context">The compilation context.</param> /// <returns></returns> public static IntermediateExpression Compile(ExpressionSyntax syntax, IMathContext context = null) { var buffer = CompilerBuffers.New(); CompileSpan(buffer, syntax, 0, syntax.Tokens.Length); return(new IntermediateExpression() { Operations = buffer.Operations.ToArray(), Static = buffer.Src.ToArray(), DistSize = buffer.Dist.Count, Import = context.ResolveTerms(syntax.Terms), actions = new IntermediateOperationActions(context) }); }
private static int FindIndexFromBuffer(CompilerBuffers buffers, ExpressionToken token) { for (int i = 0; i < buffers.Src.Count; i++) { var src = buffers.Src[i]; if (src.ValueClass != token.Value.ValueClass) { continue; } switch (src.ValueClass) { case ValueClassifier.None: return(i); case ValueClassifier.Boolean: if (src.BoolValue == token.Value.BoolValue) { return(i); } break; case ValueClassifier.Float: case ValueClassifier.FloatFractional: if (src.FloatValue == token.Value.FloatValue) { return(i); } break; case ValueClassifier.Int: case ValueClassifier.IntFractional: if (src.IntValue == token.Value.IntValue) { return(i); } break; } } return(-1); }
private static IntermediateParameter DescribeIndex(ExpressionSyntax syntax, CompilerBuffers buffers, int index) { for (byte i = 0; i < buffers.Dist.Count; i++) { var span = buffers.Dist[i]; if (span.Contains(index)) { return(new IntermediateParameter(IntermediateSource.Output, i)); } } var token = syntax.Tokens[index]; if (token.Operation == SyntaxTokenKind.Value) { int valueIndex = FindIndexFromBuffer(buffers, token); if (valueIndex == -1) { valueIndex = buffers.Src.Count; buffers.Src.Add(token.Value); } return(new IntermediateParameter(IntermediateSource.Static, (byte)valueIndex)); } if (token.Operation == SyntaxTokenKind.Source) { if (token.Multiplier == -1) { return(new IntermediateParameter(IntermediateSource.ImportNegated, token.Source)); } else { return(new IntermediateParameter(IntermediateSource.Import, token.Source)); } } throw new InvalidOperationException(string.Format("Unrecognised token \"{0}\" in {1}", token, syntax)); }
private static int CompileSpan(CompilerBuffers buffer, ExpressionSyntax syntax, int start, int length) { if (length == 0) { throw new InvalidOperationException("Trying to calculate with 0 length span"); } if (length == 1) { var singleParameter = DescribeIndex(syntax, buffer, start); var singleSpan = Spread(buffer.Dist, (byte)start, 1); buffer.Parameters.Add(singleParameter); var intermediateOperationCode = IntermediateOperationCode.Copy; var intermediateOperation = new IntermediateOperation(singleSpan.Index, intermediateOperationCode, buffer.Parameters.ToArray()); buffer.Parameters.Clear(); buffer.Operations.Add(intermediateOperation); return(singleSpan.Index); } int spanEnd = start + length; int depth = 0; int parenthesesStart = -1; for (int i = start; i < spanEnd; i++) { switch (syntax.Tokens[i].Operation) { case SyntaxTokenKind.OpenParentheses: if (++depth == 1) { parenthesesStart = i + 1; } break; case SyntaxTokenKind.CloseParentheses: if (--depth == 0) { int growIndex = CompileSpan(buffer, syntax, parenthesesStart, i - parenthesesStart); Grow(buffer.Dist, growIndex); } break; } } int distIndex = -1; int interations = start + length; var operatorTokens = new List <TokenReference>(interations); for (int i = start; i < interations; i++) { var token = syntax.Tokens[i]; var compiler = tokenCompilers[(int)token.Operation]; if (compiler.Pattern != OperatorPattern.None) { operatorTokens.Add(new TokenReference(i, token, compiler)); } } operatorTokens.Sort(); for (int k = 0; k < operatorTokens.Count; k++) { var tokenReference = operatorTokens[k]; int i = tokenReference.Index; var token = tokenReference.Token; if (IsIndexCalculated(buffer.Dist, i)) { continue; } DistSpan currentSpan; switch (tokenReference.Compiler.Pattern) { case OperatorPattern.Prefix: { var nextIndex = DescribeIndex(syntax, buffer, i + 1); buffer.Parameters.Add(nextIndex); currentSpan = Spread(buffer.Dist, (byte)i, 2); break; } case OperatorPattern.Conjective: { var lastIndex = DescribeIndex(syntax, buffer, i - 1); var nextIndex = DescribeIndex(syntax, buffer, i + 1); buffer.Parameters.Add(lastIndex); buffer.Parameters.Add(nextIndex); currentSpan = Spread(buffer.Dist, (byte)(i - 1), 3); break; } default: case OperatorPattern.Suffix: { var lastIndex = DescribeIndex(syntax, buffer, i - 1); buffer.Parameters.Add(lastIndex); if (operatorTokens.Count <= k - 1) { var nextToken = operatorTokens[k + 1]; if (token.Operation == SyntaxTokenKind.Percentage && nextToken.Token.Operation == SyntaxTokenKind.Source) { var nextIndex = DescribeIndex(syntax, buffer, i + 1); buffer.Parameters.Add(nextIndex); currentSpan = Spread(buffer.Dist, (byte)(i - 1), 3); } else { currentSpan = Spread(buffer.Dist, (byte)(i - 1), 2); } } else { currentSpan = Spread(buffer.Dist, (byte)(i - 1), 2); } break; } } distIndex = currentSpan.Index; var intermediateOperationCode = (IntermediateOperationCode)token.Operation; var intermediateOperation = new IntermediateOperation(currentSpan.Index, intermediateOperationCode, buffer.Parameters.ToArray()); buffer.Parameters.Clear(); buffer.Operations.Add(intermediateOperation); } return(distIndex); }