void AddOperatorToExpr(char token, int index) { // An operator can follow a number or a symbol, thus: AddOperandToExpr(); exprList.Add(CalcToken.Operator(token, index)); }
void AddSepToExpr(int index) { // An argument seperator can follow a number or a symbol, thus: AddOperandToExpr(); exprList.Add(CalcToken.ArgSeperator(index)); }
public static bool VerifySymbol(string symbol) { // Cannot contain certain reserverd characters. Or whitespace. foreach (char c in symbol) { if (CalcToken.IsOperatorChar(c) || char.IsWhiteSpace(c)) { return(false); } switch (c) { case '(': case ')': case '.': case ',': return(false); } } // It also can't be empty or start with a digit. if (symbol.Length > 0 && !char.IsDigit(symbol[0])) { return(true); } return(false); }
// ----------------------------------------- // --- Methods for multicharacter tokens --- // ----------------------------------------- void UpdateLastOperator(char c) { int lastIdx = exprList.Count - 1; var last = exprList[lastIdx]; string newOp = last.Value + c; exprList[lastIdx] = CalcToken.Operator(newOp, last.OriginIndex); }
void AddRParenToExpr(int index) { // A right parenthesis can follow a number or a symbol, thus: AddOperandToExpr(); exprList.Add(CalcToken.ParenClose(index)); // Record the closing of a subexpression to the parentheses balance. depthMeter.Pop(); }
// ------------------------------------------- // --- Methods for single character tokens --- // ------------------------------------------- void AddLParenToExpr(int index) { // A left parenthesis can follow a function, thus: bool funcSubexpr = AddFuncToExpr(); exprList.Add(CalcToken.ParenOpen(index)); // Record the opening of a subexpression to the parentheses balance. // Also record whether the subexpression we entered is associated with a function. depthMeter.Push(funcSubexpr); }
void AddNumToExpr() { if (numberStart >= 0 && tmpToken.Count > 0) { var num = new string( tmpToken.ToArray()); exprList.Add(CalcToken.Number(num, numberStart)); tmpToken.Clear(); } decimalPoint = false; numberStart = -1; }
bool AddSymToExpr(bool isFunction) { bool added = false; if (symbolStart >= 0 && tmpToken.Count > 0) { var sym = new string( tmpToken.ToArray()); if (isFunction) { exprList.Add(CalcToken.Function(sym, symbolStart)); } else { exprList.Add(CalcToken.Symbol(sym, symbolStart)); } added = true; tmpToken.Clear(); } symbolStart = -1; return(added); }
public void Push(CalcToken t) { opStack.Push(t); }
public TokenExpression Tokenize(string expr) { exprList = new List <CalcToken>(); tmpToken = new List <char>(); // Set initial values of control and housekeeping variables. TokenTypes allowedTokens = TokenTypes.ExprBegin; decimalPoint = false; numberStart = -1; symbolStart = -1; depthMeter = new Stack <bool>(); // Look-behind 1 character for double char ops. char prevc = '\0'; for (int i = 0; i < expr.Length; i++) { char c = expr[i]; // ---------------------- // ----- [1] Number ----- // ---------------------- if (char.IsDigit(c)) { if (allowedTokens.HasFlag(TokenTypes.Number)) { AddDigitToNum(c, i); // Set the allowed tokens for the next character. allowedTokens = TokenTypes.Number | TokenTypes.ExprEnd; } else { return(new TokenExpression("Unexpected number: " + c, i)); } } else if (c == '.') { if (allowedTokens.HasFlag(TokenTypes.Number)) { if (decimalPoint) { return(new TokenExpression("More than one decimal point detected", i)); } AddDotToNum(i); // Set the allowed tokens for the next character. allowedTokens = TokenTypes.Number; } else { return(new TokenExpression("Unexpected decimal point", i)); } } // --------------------------- // ----- [2] Unary Minus ----- // --------------------------- else if (c == '-' && allowedTokens.HasFlag(TokenTypes.UnaryMinus)) { exprList.Add(CalcToken.UnaryMinus(i)); } // -------------------------------- // ----- [3] Left Parenthesis ----- // -------------------------------- else if (c == '(') { if (allowedTokens.HasFlag(TokenTypes.L_Paren)) { AddLParenToExpr(i); // Set the allowed tokens for the next character. allowedTokens = TokenTypes.ExprBegin; } else { return(new TokenExpression("Unexpected left parenthesis", i)); } } // --------------------------------- // ----- [4] Right Parenthesis ----- // --------------------------------- else if (c == ')') { if (allowedTokens.HasFlag(TokenTypes.R_Paren)) { if (depthMeter.Count == 0) { return(new TokenExpression("Tried to close a subexpression before it was opened", i)); } AddRParenToExpr(i); // Set the allowed tokens for the next character. allowedTokens = TokenTypes.ExprEnd; } else { return(new TokenExpression("Unexpected right parenthesis", i)); } } // ------------------------ // ----- [5] Operator ----- // ------------------------ else if (CalcToken.IsOperatorChar(c)) { if (allowedTokens.HasFlag(TokenTypes.Operator)) { AddOperatorToExpr(c, i); // Set the allowed tokens for the next character. allowedTokens = TokenTypes.ExprBegin; } else if (CalcToken.IsDoubleOperator(prevc, c)) { UpdateLastOperator(c); // Monkey with the `c` variable, and thus the next `prevc` character. // This is to prevent operators longer than 2 chars to pass inspection. c = '\0'; } else { return(new TokenExpression("Unexpected operator: " + c, i)); } } // ----- [6] Whitespace ----- // Ignore whitespace. else if (char.IsWhiteSpace(c)) { continue; } // ---------------------------------- // ----- [7] Argument Seperator ----- // ---------------------------------- else if (c == ',') { if (allowedTokens.HasFlag(TokenTypes.R_Paren)) { if (depthMeter.Count == 0 || depthMeter.Peek() == false) { return(new TokenExpression("Illegal argument seperator", i)); } AddSepToExpr(i); // Set the allowed tokens for the next character. allowedTokens = TokenTypes.ExprBegin; } else { return(new TokenExpression("Unexpected argument seperator", i)); } } // ---------------------- // ----- [8] Symbol ----- // ---------------------- else if (allowedTokens.HasFlag(TokenTypes.Symbol)) { AddCharToSym(c, i); // Set the allowed tokens for the next character. allowedTokens = TokenTypes.Symbol | TokenTypes.L_Paren | TokenTypes.ExprEnd; } // ----- [9] Unexpected Character ----- else { return(new TokenExpression("Unexpected character: " + c, i)); } prevc = c; } // Abort on unclosed subexpression(s) / too many left parentheses. if (depthMeter.Count > 0) { return(new TokenExpression("Unclosed subexpression(s) detected, amount: " + depthMeter.Count)); } // Final check. The expression should have ended in either an operand or a right parenthesis. Both of these // set the allowedTokens to include TokenType.Operator, which would not be set by the others. So check for // that to determine whether the expression has ended correctly. if (!allowedTokens.HasFlag(TokenTypes.Operator)) { return(new TokenExpression("Expression did not end with an operand or closing parenthesis")); } AddOperandToExpr(); return(new TokenExpression(exprList)); }