private void AddToken(Token tok) { _tokenStack.Peek().AppendChild(tok); }
private Token CreateTokenTree(string cmd) { _tokenStack = new Stack<Token>(); _tokenStack.Push(new Token(TokenType.Group, "")); _pos = 0; _cmd = cmd; _cmdLength = cmd.Length; char ch, nextCh1, nextCh2, lastCh = k_nullChar; while (_pos < _cmdLength) { ch = cmd[_pos]; nextCh1 = (_pos + 1 < _cmdLength ? cmd[_pos + 1] : k_nullChar); nextCh2 = (_pos + 2 < _cmdLength ? cmd[_pos + 2] : k_nullChar); // Ignore whitespace if (Char.IsWhiteSpace(ch)) { _pos++; continue; } // In this if/else block, ensure that g_pos is always advanced under all conditions, // unless an error is thrown. if (Char.IsLetter(ch)) { GrabAlnumToken(); } else if (Char.IsDigit(ch) || ch == '.') { GrabNumberToken(); } else if (ch == '+') { if (nextCh1 == '=') { AddToken(new Token(OperatorType.AddAssign, "+=")); _pos += 2; } else { AddToken(new Token(OperatorType.Add, "+")); _pos++; } } else if (ch == '-') { if (Char.IsDigit(nextCh1) && (lastCh == k_nullChar || IsOperatorChar(lastCh))) { GrabNumberToken(); } else if (nextCh1 == '=') { AddToken(new Token(OperatorType.SubAssign, "-=")); _pos += 2; } else { AddToken(new Token(OperatorType.Sub, "-")); _pos++; } } else if (ch == '*') { if (nextCh1 == '=') { AddToken(new Token(OperatorType.MulAssign, "*=")); _pos += 2; } else { AddToken(new Token(OperatorType.Mul, "*")); _pos++; } } else if (ch == '/') { if (nextCh1 == '=') { AddToken(new Token(OperatorType.DivAssign, "/=")); _pos += 2; } else { if (Settings.UseDivForFractions) AddToken(new Token(OperatorType.Fraction, "/")); else AddToken(new Token(OperatorType.Div, "/")); _pos++; } } else if (ch == '%') { if (nextCh1 == '=') { AddToken(new Token(OperatorType.ModAssign, "%=")); _pos += 2; } else { AddToken(new Token(OperatorType.Mod, "%")); _pos++; } } else if (ch == '<') { if (nextCh1 == '<') { if (nextCh2 == '=') { AddToken(new Token(OperatorType.ShiftLeftAssign, "<<=")); _pos += 3; } else { AddToken(new Token(OperatorType.ShiftLeft, "<<")); _pos += 2; } } else if (nextCh1 == '=') { AddToken(new Token(OperatorType.LessOrEqual, "<=")); _pos += 2; } else { AddToken(new Token(OperatorType.LessThan, "<")); _pos++; } } else if (ch == '>') { if (nextCh1 == '>') { if (nextCh2 == '=') { AddToken(new Token(OperatorType.ShiftRightAssign, ">>=")); _pos += 3; } else { AddToken(new Token(OperatorType.ShiftRight, ">>")); _pos += 2; } } else if (nextCh1 == '=') { AddToken(new Token(OperatorType.GreaterOrEqual, ">=")); _pos += 2; } else { AddToken(new Token(OperatorType.GreaterThan, ">")); _pos++; } } else if (ch == '|') { if (nextCh1 == '=') { AddToken(new Token(OperatorType.BitwiseOrAssign, "|=")); _pos += 2; } else if (nextCh1 == '|') { AddToken(new Token(OperatorType.Or, "||")); _pos += 2; } else { AddToken(new Token(OperatorType.BitwiseOr, "|")); _pos++; } } else if (ch == '^') { if (nextCh1 == '=') { AddToken(new Token(Settings.EnableXor ? OperatorType.BitwiseXorAssign : OperatorType.PwrAssign, "^=")); _pos += 2; } else { AddToken(new Token(Settings.EnableXor ? OperatorType.BitwiseXor : OperatorType.Pwr, "^")); _pos++; } } else if (ch == '&') { if (nextCh1 == '=') { AddToken(new Token(OperatorType.BitwiseAndAssign, "&=")); _pos += 2; } else if (nextCh1 == '&') { AddToken(new Token(OperatorType.And, "&&")); _pos += 2; } else { AddToken(new Token(OperatorType.BitwiseAnd, "&")); _pos++; } } else if (ch == '=') { if (nextCh1 == '=') { AddToken(new Token(OperatorType.Equal, "==")); _pos += 2; } else { AddToken(new Token(OperatorType.Assign, "=")); _pos++; } } else if (ch == '(') { Token groupToken = new Token(TokenType.Group, ""); AddToken(groupToken); _tokenStack.Push(groupToken); _pos++; } else if (ch == ')') { if (_tokenStack.Count <= 1) throw new Exception("Mismatched ')'."); _tokenStack.Pop(); _pos++; } else if (ch == ',') { AddToken(new Token(OperatorType.Comma, ",")); _pos++; } else if (ch == '\\') { AddToken(new Token(OperatorType.Fraction, "\\")); _pos++; } else if (ch == '\"') { AddToken(new Token(OperatorType.Inches, "\"")); _pos++; } else if (ch == '\'') { AddToken(new Token(OperatorType.Feet, "\'")); _pos++; } else if (ch == '~') { AddToken(new Token(OperatorType.BitwiseNot, "~")); _pos++; } else if (ch == '[') { GrabDateToken(); } else if (ch == '{') { GrabTimeSpanToken(); } else if (ch == '!') { if (nextCh1 == '=') { AddToken(new Token(OperatorType.NotEqual, "!=")); _pos += 2; } else { AddToken(new Token(OperatorType.Not, "!")); _pos++; } } else if (ch == '?') { AddToken(new Token(OperatorType.Condition1, "?")); _pos++; } else if (ch == ':') { AddToken(new Token(OperatorType.Condition2, ":")); _pos++; } else { throw new Exception("Invalid char '" + ch + "'."); } lastCh = ch; } if (_tokenStack.Count != 1) throw new Exception("Mismatched '('."); return _tokenStack.Pop(); }
public Token Clone() { Token tok = new Token(_type, _text, _value != null ? _value.Clone() : null); tok._opType = _opType; tok._isFuncArgs = _isFuncArgs; if (_group != null) { foreach (Token t in _group) tok._group.Add(t.Clone()); } if (_returnValues != null) { tok._returnValues = new List<Value>(); foreach (Value v in _returnValues) tok._returnValues.Add(v.Clone()); } return tok; }
private void Execute(Token parentToken, Token leftToken2, Token leftToken, Token rightToken) { switch (_type) { case TokenType.Operator: Calc.Operator.Execute(this, parentToken, leftToken2, leftToken, rightToken); break; case TokenType.Group: if (leftToken != null && (leftToken._type == TokenType.Function || leftToken._type == TokenType.Macro)) _isFuncArgs = true; ExecuteGroup(); _precedence = 0; break; case TokenType.Function: if (rightToken == null || rightToken._returnValues == null) throw new Exception("Missing argument list for function '" + _text + "'."); _value = Function.Execute(_text, rightToken._returnValues.ToArray()); _precedence = 0; rightToken.Enabled = false; break; case TokenType.Macro: { if (rightToken == null || rightToken._returnValues == null) throw new Exception("Missing argument list for macro '" + _text + "'."); // Pretend we're a group this._type = TokenType.Group; Data.GetMacro(Text).LoadTokenGroup(this, rightToken._returnValues.ToArray()); ExecuteGroup(); if (_returnValues.Count != 1) throw new Exception("Macro '" + _text + "' syntax error."); _value = _returnValues[0]; _precedence = 0; rightToken.Enabled = false; } break; default: throw new Exception("Internal: Cannot execute token type '" + _type.ToString() + "'."); } }
public void AppendChild(Token tok) { if (_type != TokenType.Group) throw new Exception("Internal: Child tokens cannot be appended to '" + _type.ToString() + "' tokens."); if (_group == null) _group = new List<Token>(); _group.Add(tok); }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool ProcessPossibleMacro(Token tokenGroup, string source) { // Macro definitions take the form: // macroName(param1, param2, etc.)=<equation> List<Token> group = tokenGroup.Group; if (group.Count <= 3) return false; // First token must be the name if (group[0].Type != TokenType.Variable && group[0].Type != TokenType.Macro) return false; string macroName = group[0].Text; //if (Data.IsVariable(macroName)) return false; // Cannot have a macro that is the same name as a variable. // Next token must be a set of brackets if (group[1].Type != TokenType.Group) return false; // Next token must be '=' if (group[2].Type != TokenType.Operator || group[2].Operator != OperatorType.Assign) return false; // Check that arguments have correct form (arg, comma, arg, comma, ...) List<string> argNames = new List<string>(); bool lookingForArg = true; bool gotAToken = false; foreach (Token argToken in group[1].Group) { if (lookingForArg) { switch (argToken.Type) { case TokenType.Variable: case TokenType.Function: case TokenType.Macro: break; default: throw new Exception("Expected macro argument name."); } // Check for duplicate argument name foreach (string argName in argNames) { if (argName.ToLower() == argToken.Text.ToLower()) throw new Exception("Duplicate macro argument '" + argToken.Text + "'."); } argNames.Add(argToken.Text.ToLower()); } else // looking for comma { if (argToken.Type != TokenType.Operator || argToken.Operator != OperatorType.Comma) throw new Exception("Expected comma after argument."); } gotAToken = true; lookingForArg = !lookingForArg; } if (lookingForArg && gotAToken) return false; // Create a new group containing only the equation List<Token> eqGroup = new List<Token>(); int eqGroupIndex = 0; foreach (Token tok in group) { if (eqGroupIndex++ >= 3) eqGroup.Add(tok.Clone()); } PrepareMacroEquation(argNames, eqGroup); Macro macro = new Macro(macroName, argNames.ToArray(), eqGroup, source); if (Data.IsMacro(macroName)) { Data.DeleteMacro(macroName); Data.AddMacro(macro); //_macros[macroName.ToLower()] = macro; if (!Globals.silentMode) Globals.form.WriteLine(HistoryType.Info, "Replaced macro '" + macroName + "'."); } else { Data.AddMacro(macro); //_macros.Add(macroName.ToLower(), macro); if (!Globals.silentMode) Globals.form.WriteLine(HistoryType.Info, "Created macro '" + macroName + "'."); } return true; }
public void LoadTokenGroup(Token token, Value[] args) { if (args.Length != _args.Length) throw new Exception("Macro '" + _name + "' requires " + _args.Length + " argument(s)."); SortedList<string, Value> argList = new SortedList<string, Value>(); int argIndex = 0; foreach (string argName in _args) argList.Add(argName, args[argIndex++]); foreach (Token eqToken in _eqGroup) token.AppendChild(eqToken.Clone()); PrepareTokenGroupForMacroExe(token.Group, argList); }
public static void Execute(Token token, Token parent, Token left2, Token left, Token right) { _token = token; _parentToken = parent; _leftToken = left; _leftToken2 = left2; _rightToken = right; switch (token.Operator) { case OperatorType.Add: BinaryOpTest(); BinaryOp(left.Value.Add(right.Value)); break; case OperatorType.Sub: if (right == null || !right.HasValue) throw new Exception("Operator '-' expected value on right."); if (left == null || !left.HasValue) { // Unary minus operator UnaryOpTest(); UnaryOp((new Value(0, ValueFormat.Default)).Subtract(right.Value)); } else { BinaryOpTest(); BinaryOp(left.Value.Subtract(right.Value)); } break; case OperatorType.Mul: BinaryOpTest(); BinaryOp(left.Value.Multiply(right.Value)); break; case OperatorType.Div: BinaryOpTest(); BinaryOp(left.Value.Divide(right.Value)); break; case OperatorType.Mod: BinaryOpTest(); BinaryOp(left.Value.Modulus(right.Value)); break; case OperatorType.Pwr: BinaryOpTest(); BinaryOp(left.Value.Power(right.Value)); break; case OperatorType.ShiftLeft: BinaryOpTest(); BinaryOp(left.Value.ShiftLeft(right.Value)); break; case OperatorType.ShiftRight: BinaryOpTest(); BinaryOp(left.Value.ShiftRight(right.Value)); break; case OperatorType.BitwiseOr: BinaryOpTest(); BinaryOp(left.Value.BitwiseOr(right.Value)); break; case OperatorType.BitwiseAnd: BinaryOpTest(); BinaryOp(left.Value.BitwiseAnd(right.Value)); break; case OperatorType.BitwiseXor: BinaryOpTest(); BinaryOp(left.Value.BitwiseXor(right.Value)); break; case OperatorType.Assign: AssignOpTest(); AssignOp(right.Value); break; case OperatorType.AddAssign: AssignOpTest(); AssignOp(left.Value.Add(right.Value)); break; case OperatorType.SubAssign: AssignOpTest(); AssignOp(left.Value.Subtract(right.Value)); break; case OperatorType.MulAssign: AssignOpTest(); AssignOp(left.Value.Multiply(right.Value)); break; case OperatorType.DivAssign: AssignOpTest(); AssignOp(left.Value.Divide(right.Value)); break; case OperatorType.ModAssign: AssignOpTest(); AssignOp(left.Value.Modulus(right.Value)); break; case OperatorType.PwrAssign: AssignOpTest(); AssignOp(left.Value.Power(right.Value)); break; case OperatorType.ShiftLeftAssign: AssignOpTest(); AssignOp(left.Value.ShiftLeft(right.Value)); break; case OperatorType.ShiftRightAssign: AssignOpTest(); AssignOp(left.Value.ShiftRight(right.Value)); break; case OperatorType.BitwiseOrAssign: AssignOpTest(); AssignOp(left.Value.BitwiseOr(right.Value)); break; case OperatorType.BitwiseAndAssign: AssignOpTest(); AssignOp(left.Value.BitwiseAnd(right.Value)); break; case OperatorType.BitwiseXorAssign: AssignOpTest(); AssignOp(left.Value.BitwiseXor(right.Value)); break; case OperatorType.BitwiseNot: UnaryOpTest(); UnaryOp(right.Value.BitwiseNot()); break; case OperatorType.Fraction: { BinaryOpTest(); decimal num = left.Value.DecValue; decimal denom = right.Value.DecValue; if (left2 != null && left2.HasValue) { decimal whole = left2.Value.DecValue; if (whole < 0) num = whole * denom - num; else num += whole * denom; left2.Enabled = false; } BinaryOp(new Value(num, denom, ValueFormat.Fraction)); } break; case OperatorType.Inches: { if (left == null || !left.HasValue) throw new Exception("Operator '\"' expected value on left."); Value val; if (left.Value.IsFractional) { val = left.Value.Clone(); val.Format = ValueFormat.Inches; } else if (left.Value.IsInteger) { val = Value.CreateFraction(left.Value, new Value(1, ValueFormat.Default)); val.Format = ValueFormat.Inches; } else throw new Exception("Operator '\"' expected an integer or fraction on left."); SetValue(token, val); left.Enabled = false; } break; case OperatorType.Feet: { if (left == null || !left.HasValue) throw new Exception("Operator ' expected value on left."); if (!left.Value.IsFractional & !left.Value.IsInteger) throw new Exception("Operator ' expected an integer or fraction on left."); Value val = Value.CreateFraction(left.Value, new Value(1, ValueFormat.Default)).Multiply(new Value(12, ValueFormat.Default)); val.Format = ValueFormat.Inches; left.Enabled = false; if (right != null && right.HasValue && (right.Value.Format == ValueFormat.Inches)) { val = val.Add(right.Value); right.Enabled = false; } SetValue(token, val); } break; case OperatorType.Comma: // Hack for digit grouping. Only to be performed when not inside a function argument group. if (Settings.DigitGrouping && !parent.IsFuncArgs) { if (left != null && left.HasValue && right != null && right.HasValue) { Value leftValue = left.Value; Value rightValue = right.Value; if (leftValue.IsInteger && (leftValue.Format == ValueFormat.Dec || leftValue.Format == ValueFormat.Default) && (rightValue.Format == ValueFormat.Dec || rightValue.Format == ValueFormat.Default)) { SetValue(token, leftValue.Multiply(new Value(1000, ValueFormat.Default)).Add(rightValue)); left.Enabled = false; right.Enabled = false; } } } token.Precedence = 0; break; case OperatorType.Equal: BinaryOpTest(); BinaryOp(new Value(left.Value.DecValue == right.Value.DecValue ? 1 : 0, ValueFormat.Default)); break; case OperatorType.NotEqual: BinaryOpTest(); BinaryOp(new Value(left.Value.DecValue != right.Value.DecValue ? 1 : 0, ValueFormat.Default)); break; case OperatorType.LessThan: BinaryOpTest(); BinaryOp(new Value(left.Value.DecValue < right.Value.DecValue ? 1 : 0, ValueFormat.Default)); break; case OperatorType.LessOrEqual: BinaryOpTest(); BinaryOp(new Value(left.Value.DecValue <= right.Value.DecValue ? 1 : 0, ValueFormat.Default)); break; case OperatorType.GreaterThan: BinaryOpTest(); BinaryOp(new Value(left.Value.DecValue > right.Value.DecValue ? 1 : 0, ValueFormat.Default)); break; case OperatorType.GreaterOrEqual: BinaryOpTest(); BinaryOp(new Value(left.Value.DecValue >= right.Value.DecValue ? 1 : 0, ValueFormat.Default)); break; case OperatorType.Not: UnaryOpTest(); UnaryOp(new Value(right.Value.DecValue == 0 ? 1 : 0, ValueFormat.Default)); break; case OperatorType.And: BinaryOpTest(); BinaryOp(new Value(left.Value.DecValue != 0 && right.Value.DecValue != 0 ? 1 : 0, ValueFormat.Default)); break; case OperatorType.Or: BinaryOpTest(); BinaryOp(new Value(left.Value.DecValue != 0 || right.Value.DecValue != 0 ? 1 : 0, ValueFormat.Default)); break; case OperatorType.Condition1: BinaryOpTest(); if (left.Value.DecValue != 0) SetValue(token, new Value(1, ValueFormat.Default)); else SetValue(token, new Value(0, ValueFormat.Default)); left.Enabled = false; break; case OperatorType.Condition2: if (left == null || !left.HasValue) throw new Exception("Operator ':' expected value on left."); if (right == null || !right.HasValue) throw new Exception("Operator ':' expected value on right."); if (left2 == null || left2.Type != TokenType.Operator || left2.Operator != OperatorType.Condition1) throw new Exception("Operator ':' expected '?' to the left."); SetValue(token, left2.Value.DecValue != 0 ? left.Value.Clone() : right.Value.Clone()); left.Enabled = left2.Enabled = right.Enabled = false; break; } }
private static void SetValue(Token tok, Value val) { tok.Value = val; //tok.Type = TokenType.None; tok.Precedence = 0; }