/// <summary> /// Split an expression into tokens /// </summary> public static List<Token> Tokens(this string input) { // (strings) | (nums, funcs, vars) | (sci nums) var r = new Regex(@"(\['.*?'\])|([^0-9a-zA-Z.\$])|([0-9.]+e[+\-]?[0-9]+)"); // anything but alpha numeric or decimals gets split var output = new List<Token>(); // return splits, including split characters (because of capture group in regex) string[] frags = r.Split(input); foreach (string frag in frags) { if (String.IsNullOrEmpty(frag)) continue; var t = new Token(frag); var last = (output.Count > 0) ? (output.Last()) : (null); #region check for uniary prefix operators if (t.Class == TokenClass.BinaryOperator) { if (output.Count < 1) { t.Class = TokenClass.UniaryPrefix; } else { if (last != null) switch (last.Class) { case TokenClass.BinaryOperator: case TokenClass.UniaryPostfix: case TokenClass.OpenBracket: case TokenClass.ArgumentSeperator: t.Class = TokenClass.UniaryPrefix; break; } } } #endregion #region check for functions // a name followed by an open bracket is taken to be a function if (last != null) if (t.Class == TokenClass.OpenBracket && output.Count > 0 && last.Class == TokenClass.Name) { last.Class = TokenClass.Function; last.Value = "/" + last; // easier to find functions, plus vars and fucntions can share a name } #endregion output.Add(t); } return output; }
/// <summary> /// Compare precedence, taking associativity into account /// </summary> public bool ShouldDisplace(Token other) { if (other.Class != TokenClass.BinaryOperator) return false; if (Direction == Association.LeftToRight) { return other.Precedence >= Precedence; } return other.Precedence > Precedence; }