Skip to content

Commit 4f3570c

Browse files
committed
Bug fix for negative numbers
Fixing bug in handling negative numbers where a minus sign was mistook for a negative sign.
1 parent 46866fc commit 4f3570c

File tree

2 files changed

+48
-51
lines changed

2 files changed

+48
-51
lines changed

Source/LoreSoft.MathExpressions.Tests/MathEvaluatorTest.cs

+5-10
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,21 @@ public void EvaluateNegative()
2828
{
2929
double expected = 2d + -1d;
3030
double result = eval.Evaluate("2 + -1");
31-
3231
Assert.AreEqual(expected, result);
3332

3433
expected = -2d + 1d;
3534
result = eval.Evaluate("-2 + 1");
36-
3735
Assert.AreEqual(expected, result);
3836

39-
4037
expected = (2d + -1d) * (-1d + 2d);
4138
result = eval.Evaluate("(2 + -1) * (-1 + 2)");
42-
4339
Assert.AreEqual(expected, result);
44-
}
4540

46-
[Test]
47-
public void EvaluateNegative2()
48-
{
49-
double result = eval.Evaluate("(-4-3) *5");
50-
Assert.AreEqual(-35d, result);
41+
// this failed due to a bug in parsing whereby the minus sign was erroneously mistaken for a negative sign.
42+
// which left the -4 on the calculationStack at the end of evaluation.
43+
expected = (-4 - 3) * 5;
44+
result = eval.Evaluate("(-4-3) *5");
45+
Assert.AreEqual(expected, result);
5146
}
5247

5348
[Test]

Source/LoreSoft.MathExpressions/MathEvaluator.cs

+43-41
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public class MathEvaluator : IDisposable
4343
private List<string> _innerFunctions;
4444
private uint _nestedFunctionDepth;
4545
private StringReader _expressionReader;
46+
private VariableDictionary _variables;
47+
private ReadOnlyCollection<string> _functions;
48+
private char _currentChar;
49+
4650

4751
/// <summary>
4852
/// Initializes a new instance of the <see cref="MathEvaluator"/> class.
@@ -62,7 +66,6 @@ public MathEvaluator()
6266
_nestedFunctionDepth = 0;
6367
}
6468

65-
private VariableDictionary _variables;
6669

6770
/// <summary>
6871
/// Gets the variables collections.
@@ -73,8 +76,6 @@ public VariableDictionary Variables
7376
get { return _variables; }
7477
}
7578

76-
private ReadOnlyCollection<string> _functions;
77-
7879
/// <summary>Gets the functions available to <see cref="MathEvaluator"/>.</summary>
7980
/// <value>The functions for <see cref="MathEvaluator"/>.</value>
8081
/// <seealso cref="RegisterFunction"/>
@@ -149,54 +150,54 @@ internal bool IsFunction(string name)
149150

150151
private void ParseExpressionToQueue()
151152
{
152-
char l = '\0';
153-
char c = '\0';
153+
char lastChar = '\0';
154+
_currentChar = '\0';
154155

155156
do
156157
{
157158
// last non white space char
158-
if (!char.IsWhiteSpace(c))
159-
l = c;
159+
if (!char.IsWhiteSpace(_currentChar))
160+
lastChar = _currentChar;
160161

161-
c = (char)_expressionReader.Read();
162+
_currentChar = (char)_expressionReader.Read();
162163

163-
if (char.IsWhiteSpace(c))
164+
if (char.IsWhiteSpace(_currentChar))
164165
continue;
165166

166-
if (TryNumber(c, l))
167+
if (TryNumber(lastChar))
167168
continue;
168169

169-
if (TryString(c))
170+
if (TryString())
170171
continue;
171172

172-
if (TryStartGroup(c))
173+
if (TryStartGroup())
173174
continue;
174175

175-
if (TryComma(c))
176+
if (TryComma())
176177
continue;
177178

178-
if (TryOperator(c))
179+
if (TryOperator())
179180
continue;
180181

181-
if (TryEndGroup(c))
182+
if (TryEndGroup())
182183
continue;
183184

184-
if (TryConvert(c))
185+
if (TryConvert())
185186
continue;
186187

187-
throw new ParseException(Resources.InvalidCharacterEncountered + c);
188+
throw new ParseException(Resources.InvalidCharacterEncountered + _currentChar);
188189
} while (_expressionReader.Peek() != -1);
189190

190191
ProcessSymbolStack();
191192
}
192193

193-
private bool TryConvert(char c)
194+
private bool TryConvert()
194195
{
195-
if (c != '[')
196+
if (_currentChar != '[')
196197
return false;
197198

198199
_buffer.Length = 0;
199-
_buffer.Append(c);
200+
_buffer.Append(_currentChar);
200201

201202
char p = (char)_expressionReader.Peek();
202203
while (char.IsLetter(p) || char.IsWhiteSpace(p) || p == '-' || p == '>' || p == ']')
@@ -222,13 +223,13 @@ private bool TryConvert(char c)
222223
throw new ParseException(Resources.InvalidConvertionExpression + _buffer);
223224
}
224225

225-
private bool TryString(char c)
226+
private bool TryString()
226227
{
227-
if (!char.IsLetter(c))
228+
if (!char.IsLetter(_currentChar))
228229
return false;
229230

230231
_buffer.Length = 0;
231-
_buffer.Append(c);
232+
_buffer.Append(_currentChar);
232233

233234
char p = (char)_expressionReader.Peek();
234235
while (char.IsLetter(p) || char.IsNumber(p))
@@ -256,34 +257,34 @@ private bool TryString(char c)
256257
throw new ParseException(Resources.InvalidVariableEncountered + _buffer);
257258
}
258259

259-
private bool TryStartGroup(char c)
260+
private bool TryStartGroup()
260261
{
261-
if (c != '(')
262+
if (_currentChar != '(')
262263
return false;
263264

264265
if (PeekNextNonWhitespaceChar() == ',')
265266
{
266267
throw new ParseException(Resources.InvalidCharacterEncountered + ",");
267268
}
268269

269-
_symbolStack.Push(c.ToString());
270+
_symbolStack.Push(_currentChar.ToString());
270271
return true;
271272
}
272273

273-
private bool TryComma(char c)
274+
private bool TryComma()
274275
{
275-
if (c != ',')
276+
if (_currentChar != ',')
276277
return false;
277278

278279
if (_nestedFunctionDepth <= 0)
279280
{
280-
throw new ParseException(Resources.InvalidCharacterEncountered + c);
281+
throw new ParseException(Resources.InvalidCharacterEncountered + _currentChar);
281282
}
282283

283284
char nextChar = PeekNextNonWhitespaceChar();
284285
if (nextChar == ')' || nextChar == ',')
285286
{
286-
throw new ParseException(Resources.InvalidCharacterEncountered + c);
287+
throw new ParseException(Resources.InvalidCharacterEncountered + _currentChar);
287288
}
288289

289290
return true;
@@ -301,9 +302,9 @@ private char PeekNextNonWhitespaceChar()
301302
}
302303

303304

304-
private bool TryEndGroup(char c)
305+
private bool TryEndGroup()
305306
{
306-
if (c != ')')
307+
if (_currentChar != ')')
307308
return false;
308309

309310
bool hasStart = false;
@@ -340,13 +341,13 @@ private bool TryEndGroup(char c)
340341
return true;
341342
}
342343

343-
private bool TryOperator(char c)
344+
private bool TryOperator()
344345
{
345-
if (!OperatorExpression.IsSymbol(c))
346+
if (!OperatorExpression.IsSymbol(_currentChar))
346347
return false;
347348

348349
bool repeat;
349-
string s = c.ToString();
350+
string s = _currentChar.ToString();
350351

351352
do
352353
{
@@ -369,23 +370,24 @@ private bool TryOperator(char c)
369370
return true;
370371
}
371372

372-
private bool TryNumber(char c, char l)
373+
private bool TryNumber(char lastChar)
373374
{
374-
bool isNumber = NumberExpression.IsNumber(c);
375+
bool isNumber = NumberExpression.IsNumber(_currentChar);
375376
// only negative when last char is group start or symbol
376-
bool isNegative = NumberExpression.IsNegativeSign(c) &&
377-
(l == '\0' || l == '(' || OperatorExpression.IsSymbol(l));
377+
bool isNegative = NumberExpression.IsNegativeSign(_currentChar) &&
378+
(lastChar == '\0' || lastChar == '(' || OperatorExpression.IsSymbol(lastChar));
378379

379380
if (!isNumber && !isNegative)
380381
return false;
381382

382383
_buffer.Length = 0;
383-
_buffer.Append(c);
384+
_buffer.Append(_currentChar);
384385

385386
char p = (char)_expressionReader.Peek();
386387
while (NumberExpression.IsNumber(p))
387388
{
388-
_buffer.Append((char)_expressionReader.Read());
389+
_currentChar = (char) _expressionReader.Read();
390+
_buffer.Append(_currentChar);
389391
p = (char)_expressionReader.Peek();
390392
}
391393

0 commit comments

Comments
 (0)