From 3fa6e9d4916dc1c0798ca570168e5c69a73762d6 Mon Sep 17 00:00:00 2001 From: Mariusz Gromada Date: Fri, 20 May 2022 23:29:22 +0200 Subject: [PATCH] Fixed: checkSyntax does not works fully correctly with implied multiplication expression string, but disabled implied multiplication option #259 --- .../mariuszgromada/math/mxparser/Argument.cs | 2 +- .../math/mxparser/Expression.cs | 106 ++++++++++------ .../mariuszgromada/math/mxparser/Function.cs | 2 +- .../4-Unit-Tests/SyntaxTest.cs | 62 +++++++++- .../math/mxparser/Argument.java | 2 +- .../math/mxparser/Expression.java | 114 +++++++++++------- .../math/mxparser/Function.java | 2 +- .../math/mxparser/test/SyntaxTest.java | 62 +++++++++- 8 files changed, 264 insertions(+), 88 deletions(-) diff --git a/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Argument.cs b/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Argument.cs index 8d4515ad..5925a691 100644 --- a/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Argument.cs +++ b/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Argument.cs @@ -208,7 +208,7 @@ namespace org.mariuszgromada.math.mxparser { * Scalar Pro
* MathSpace.pl
* - * @version 5.0.0 + * @version 5.0.3 * * @see RecursiveArgument * @see Expression diff --git a/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Expression.cs b/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Expression.cs index aad635d8..4503719d 100644 --- a/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Expression.cs +++ b/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Expression.cs @@ -196,7 +196,7 @@ namespace org.mariuszgromada.math.mxparser { * Scalar Pro
* MathSpace.pl
* - * @version 5.0.2 + * @version 5.0.3 * * @see Argument * @see RecursiveArgument @@ -337,6 +337,11 @@ public class Expression : PrimitiveElement { * Implied multiplication mode */ private bool impliedMultiplicationMode = mXparser.impliedMultiplicationMode; + /** + * Fires an error when impliedMultiplicationMode is on + * and there is a missing multiplication operator + */ + private bool impliedMultiplicationError = false; /** * Internal parameter for calculus expressions * to avoid decrease in accuracy. @@ -5313,6 +5318,10 @@ private bool checkSyntax(String level, bool functionWithBodyExt) { * IF there are no lex error */ tokenizeExpressionString(); + if (!impliedMultiplicationMode && impliedMultiplicationError) { + syntax = SYNTAX_ERROR_OR_STATUS_UNKNOWN; + errorMessage = errorMessage + level + "Multiplication operator missing - try Implied Multiplication Mode." + "\n"; + } /* * Duplicated tokens? */ @@ -7467,76 +7476,98 @@ private void initialTokensAdd(Token token) { return; } /* Start: Implied Multiplication related part*/ - if (impliedMultiplicationMode) { - Token precedingToken = initialTokens[initialTokens.Count - 1]; - if (token.isSpecialTokenName()) { - /* Special constant case [...] - * Excluding: '([a]', ';[a]', ',[a]', '+[a]', .... - */ - if (!precedingToken.isLeftParenthesis() && - !precedingToken.isBinaryOperator() && - !precedingToken.isParameterSeparator() && - !precedingToken.isUnaryLeftOperator()) { + Token precedingToken = initialTokens[initialTokens.Count - 1]; + if (token.isSpecialTokenName()) { + /* Special constant case [...] + * Excluding: '([a]', ';[a]', ',[a]', '+[a]', .... + */ + if (!precedingToken.isLeftParenthesis() && + !precedingToken.isBinaryOperator() && + !precedingToken.isParameterSeparator() && + !precedingToken.isUnaryLeftOperator()) { + if (impliedMultiplicationMode) { initialTokens.Add(Token.makeMultiplyToken()); initialTokens.Add(token); return; } + else impliedMultiplicationError = true; } - else if (precedingToken.isSpecialTokenName()) { - if (!token.isRightParenthesis() && - !token.isBinaryOperator() && - !token.isParameterSeparator() && - !token.isUnaryRightOperator()) { + } + else if (precedingToken.isSpecialTokenName()) { + if (!token.isRightParenthesis() && + !token.isBinaryOperator() && + !token.isParameterSeparator() && + !token.isUnaryRightOperator()) { + if (impliedMultiplicationMode) { initialTokens.Add(Token.makeMultiplyToken()); initialTokens.Add(token); return; } + else impliedMultiplicationError = true; } - else if (token.isLeftParenthesis()) { - // ')(' case - if (precedingToken.isRightParenthesis()) { + } + else if (token.isLeftParenthesis()) { + // ')(' case + if (precedingToken.isRightParenthesis()) { + if (impliedMultiplicationMode) { initialTokens.Add(Token.makeMultiplyToken()); initialTokens.Add(token); return; } - // '2(' case - if (precedingToken.isNumber()) { + else impliedMultiplicationError = true; + } + // '2(' case + if (precedingToken.isNumber()) { + if (impliedMultiplicationMode) { initialTokens.Add(Token.makeMultiplyToken()); initialTokens.Add(token); return; } - // 'e(', 'pi(' cases - if (precedingToken.isIdentifier()) { + else impliedMultiplicationError = true; + } + // 'e(', 'pi(' cases + if (precedingToken.isIdentifier()) { + if (impliedMultiplicationMode) { initialTokens.Add(Token.makeMultiplyToken()); initialTokens.Add(token); return; } - } else if (precedingToken.isRightParenthesis()) { - // ')2', ')h.1212', ')1_2_3' cases - if (token.isNumber()) { + else impliedMultiplicationError = true; + } + } else if (precedingToken.isRightParenthesis()) { + // ')2', ')h.1212', ')1_2_3' cases + if (token.isNumber()) { + if (impliedMultiplicationMode) { initialTokens.Add(Token.makeMultiplyToken()); initialTokens.Add(token); return; } - // ')x', ')sin(x)', ')[sdf]' cases - if (!token.isParameterSeparator() && - !token.isBinaryOperator() && - !token.isUnaryRightOperator() && - !token.isRightParenthesis()) { + else impliedMultiplicationError = true; + } + // ')x', ')sin(x)', ')[sdf]' cases + if (!token.isParameterSeparator() && + !token.isBinaryOperator() && + !token.isUnaryRightOperator() && + !token.isRightParenthesis()) { + if (impliedMultiplicationMode) { initialTokens.Add(Token.makeMultiplyToken()); initialTokens.Add(token); return; } - } else if (token.isUnicodeRootOperator()) { - /* Unicode root operator */ - if (!precedingToken.isLeftParenthesis() && - !precedingToken.isBinaryOperator() && - !precedingToken.isParameterSeparator() && - !precedingToken.isUnaryLeftOperator()) { + else impliedMultiplicationError = true; + } + } else if (token.isUnicodeRootOperator()) { + /* Unicode root operator */ + if (!precedingToken.isLeftParenthesis() && + !precedingToken.isBinaryOperator() && + !precedingToken.isParameterSeparator() && + !precedingToken.isUnaryLeftOperator()) { + if (impliedMultiplicationMode) { initialTokens.Add(Token.makeMultiplyToken()); initialTokens.Add(token); return; } + else impliedMultiplicationError = true; } } /* End: Implied Multiplication related part*/ @@ -7989,6 +8020,7 @@ private static bool isBlankChar(char c) { * Tokenizing expressiong string */ private void tokenizeExpressionString() { + impliedMultiplicationError = false; /* * Add parser and argument key words */ diff --git a/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Function.cs b/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Function.cs index a2b9b874..d0fb4f95 100644 --- a/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Function.cs +++ b/CURRENT/c-sharp/src/org/mariuszgromada/math/mxparser/Function.cs @@ -197,7 +197,7 @@ namespace org.mariuszgromada.math.mxparser { * Scalar Pro
* MathSpace.pl
* - * @version 5.0.0 + * @version 5.0.3 * * @see RecursiveArgument * @see Expression diff --git a/CURRENT/c-sharp/tests-and-release/4-Unit-Tests/SyntaxTest.cs b/CURRENT/c-sharp/tests-and-release/4-Unit-Tests/SyntaxTest.cs index 0cec45ac..19a39fdf 100644 --- a/CURRENT/c-sharp/tests-and-release/4-Unit-Tests/SyntaxTest.cs +++ b/CURRENT/c-sharp/tests-and-release/4-Unit-Tests/SyntaxTest.cs @@ -179,7 +179,7 @@ namespace org.mariuszgromada.math.mxparser.test { * Scalar Pro
* MathSpace.pl
* - * @version 5.0.0 + * @version 5.0.3 * */ [TestClass] @@ -4673,5 +4673,65 @@ public void testSyn0304() { TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); Assert.IsTrue(testResult); } + [TestMethod] + public void testSyn0305() { + TestCommonTools.testSynSettingsInit(); + bool testResult = false; + String expStr = "2pi+3e"; + TestCommonTools.consolePrintTestSynStart(305, expStr); + Expression e = new Expression(expStr); + e.enableImpliedMultiplicationMode(); + bool syn = e.checkSyntax(); + bool reg = true; + if (syn == reg) + testResult = true; + TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); + Assert.IsTrue(testResult); + } + [TestMethod] + public void testSyn0306() { + TestCommonTools.testSynSettingsInit(); + bool testResult = false; + String expStr = "2pi+3e"; + TestCommonTools.consolePrintTestSynStart(306, expStr); + Expression e = new Expression(expStr); + e.disableImpliedMultiplicationMode(); + bool syn = e.checkSyntax(); + bool reg = false; + if (syn == reg) + testResult = true; + TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); + Assert.IsTrue(testResult); + } + [TestMethod] + public void testSyn0307() { + TestCommonTools.testSynSettingsInit(); + bool testResult = false; + String expStr = "2(3+4)5"; + TestCommonTools.consolePrintTestSynStart(307, expStr); + Expression e = new Expression(expStr); + e.enableImpliedMultiplicationMode(); + bool syn = e.checkSyntax(); + bool reg = true; + if (syn == reg) + testResult = true; + TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); + Assert.IsTrue(testResult); + } + [TestMethod] + public void testSyn0308() { + TestCommonTools.testSynSettingsInit(); + bool testResult = false; + String expStr = "2(3+4)5"; + TestCommonTools.consolePrintTestSynStart(308, expStr); + Expression e = new Expression(expStr); + e.disableImpliedMultiplicationMode(); + bool syn = e.checkSyntax(); + bool reg = false; + if (syn == reg) + testResult = true; + TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); + Assert.IsTrue(testResult); + } } } diff --git a/CURRENT/java/src/org/mariuszgromada/math/mxparser/Argument.java b/CURRENT/java/src/org/mariuszgromada/math/mxparser/Argument.java index 4e4db8f0..c69eb3bd 100644 --- a/CURRENT/java/src/org/mariuszgromada/math/mxparser/Argument.java +++ b/CURRENT/java/src/org/mariuszgromada/math/mxparser/Argument.java @@ -207,7 +207,7 @@ * Scalar Pro
* MathSpace.pl
* - * @version 5.0.0 + * @version 5.0.3 * * @see RecursiveArgument * @see Expression diff --git a/CURRENT/java/src/org/mariuszgromada/math/mxparser/Expression.java b/CURRENT/java/src/org/mariuszgromada/math/mxparser/Expression.java index a7bf3432..a5071650 100644 --- a/CURRENT/java/src/org/mariuszgromada/math/mxparser/Expression.java +++ b/CURRENT/java/src/org/mariuszgromada/math/mxparser/Expression.java @@ -218,7 +218,7 @@ * Scalar Pro
* MathSpace.pl
* - * @version 5.0.2 + * @version 5.0.3 * * @see Argument * @see RecursiveArgument @@ -358,6 +358,11 @@ public class Expression extends PrimitiveElement { * Implied multiplication mode */ private boolean impliedMultiplicationMode = mXparser.impliedMultiplicationMode; + /** + * Fires an error when impliedMultiplicationMode is on + * and there is a missing multiplication operator + */ + private boolean impliedMultiplicationError = false; /** * Internal parameter for calculus expressions * to avoid decrease in accuracy. @@ -5345,6 +5350,10 @@ private boolean checkSyntax(String level, boolean functionWithBodyExt) { * IF there are no lex error */ tokenizeExpressionString(); + if (!impliedMultiplicationMode && impliedMultiplicationError) { + syntax = SYNTAX_ERROR_OR_STATUS_UNKNOWN; + errorMessage = errorMessage + level + "Multiplication operator missing - try Implied Multiplication Mode." + "\n"; + } /* * Duplicated tokens? */ @@ -7487,74 +7496,88 @@ private void initialTokensAdd(Token token) { return; } /* Start: Implied Multiplication related part*/ - if (impliedMultiplicationMode) { - Token precedingToken = initialTokens.get(initialTokens.size() - 1); - if (token.isSpecialTokenName()) { - /* Special constant case [...] - * Excluding: '([a]', ';[a]', ',[a]', '+[a]', .... - */ - if (!precedingToken.isLeftParenthesis() && - !precedingToken.isBinaryOperator() && - !precedingToken.isParameterSeparator() && - !precedingToken.isUnaryLeftOperator()) { + Token precedingToken = initialTokens.get(initialTokens.size() - 1); + if (token.isSpecialTokenName()) { + /* Special constant case [...] + * Excluding: '([a]', ';[a]', ',[a]', '+[a]', .... + */ + if (!precedingToken.isLeftParenthesis() && + !precedingToken.isBinaryOperator() && + !precedingToken.isParameterSeparator() && + !precedingToken.isUnaryLeftOperator()) { + if (impliedMultiplicationMode) { initialTokens.add(Token.makeMultiplyToken()); initialTokens.add(token); return; - } - } else if (precedingToken.isSpecialTokenName()) { - if (!token.isRightParenthesis() && - !token.isBinaryOperator() && - !token.isParameterSeparator() && - !token.isUnaryRightOperator()) { + } else impliedMultiplicationError = true; + } + } else if (precedingToken.isSpecialTokenName()) { + if (!token.isRightParenthesis() && + !token.isBinaryOperator() && + !token.isParameterSeparator() && + !token.isUnaryRightOperator()) { + if (impliedMultiplicationMode) { initialTokens.add(Token.makeMultiplyToken()); initialTokens.add(token); return; - } - } else if (token.isLeftParenthesis()) { - // ')(' case - if (precedingToken.isRightParenthesis()) { + } else impliedMultiplicationError = true; + } + } else if (token.isLeftParenthesis()) { + // ')(' case + if (precedingToken.isRightParenthesis()) { + if (impliedMultiplicationMode) { initialTokens.add(Token.makeMultiplyToken()); initialTokens.add(token); return; - } - // '2(' case - if (precedingToken.isNumber()) { + } else impliedMultiplicationError = true; + } + // '2(' case + if (precedingToken.isNumber()) { + if (impliedMultiplicationMode) { initialTokens.add(Token.makeMultiplyToken()); initialTokens.add(token); return; - } - // 'e(', 'pi(' cases - if (precedingToken.isIdentifier()) { + } else impliedMultiplicationError = true; + } + // 'e(', 'pi(' cases + if (precedingToken.isIdentifier()) { + if (impliedMultiplicationMode) { initialTokens.add(Token.makeMultiplyToken()); initialTokens.add(token); return; - } - } else if (precedingToken.isRightParenthesis()) { - // ')2', ')h.1212', ')1_2_3' cases - if (token.isNumber()) { + } else impliedMultiplicationError = true; + } + } else if (precedingToken.isRightParenthesis()) { + // ')2', ')h.1212', ')1_2_3' cases + if (token.isNumber()) { + if (impliedMultiplicationMode) { initialTokens.add(Token.makeMultiplyToken()); initialTokens.add(token); return; - } - // ')x', ')sin(x)', ')[sdf]' cases - if (!token.isParameterSeparator() && - !token.isBinaryOperator() && - !token.isUnaryRightOperator() && - !token.isRightParenthesis()) { + } else impliedMultiplicationError = true; + } + // ')x', ')sin(x)', ')[sdf]' cases + if (!token.isParameterSeparator() && + !token.isBinaryOperator() && + !token.isUnaryRightOperator() && + !token.isRightParenthesis()) { + if (impliedMultiplicationMode) { initialTokens.add(Token.makeMultiplyToken()); initialTokens.add(token); return; - } - } else if (token.isUnicodeRootOperator()) { - /* Unicode root operator */ - if (!precedingToken.isLeftParenthesis() && - !precedingToken.isBinaryOperator() && - !precedingToken.isParameterSeparator() && - !precedingToken.isUnaryLeftOperator()) { + } else impliedMultiplicationError = true; + } + } else if (token.isUnicodeRootOperator()) { + /* Unicode root operator */ + if (!precedingToken.isLeftParenthesis() && + !precedingToken.isBinaryOperator() && + !precedingToken.isParameterSeparator() && + !precedingToken.isUnaryLeftOperator()) { + if (impliedMultiplicationMode) { initialTokens.add(Token.makeMultiplyToken()); initialTokens.add(token); return; - } + } else impliedMultiplicationError = true; } } /* End: Implied Multiplication related part*/ @@ -8003,6 +8026,7 @@ private static boolean isBlankChar(char c) { * Tokenizing expression string */ private void tokenizeExpressionString() { + impliedMultiplicationError = false; /* * Add parser and argument key words */ diff --git a/CURRENT/java/src/org/mariuszgromada/math/mxparser/Function.java b/CURRENT/java/src/org/mariuszgromada/math/mxparser/Function.java index 5bab10b8..3cfafa3a 100644 --- a/CURRENT/java/src/org/mariuszgromada/math/mxparser/Function.java +++ b/CURRENT/java/src/org/mariuszgromada/math/mxparser/Function.java @@ -198,7 +198,7 @@ * Scalar Pro
* MathSpace.pl
* - * @version 5.0.0 + * @version 5.0.3 * * @see RecursiveArgument * @see Expression diff --git a/CURRENT/java/test/org/mariuszgromada/math/mxparser/test/SyntaxTest.java b/CURRENT/java/test/org/mariuszgromada/math/mxparser/test/SyntaxTest.java index 85ea0fce..42060602 100644 --- a/CURRENT/java/test/org/mariuszgromada/math/mxparser/test/SyntaxTest.java +++ b/CURRENT/java/test/org/mariuszgromada/math/mxparser/test/SyntaxTest.java @@ -178,7 +178,7 @@ * Scalar Pro
* MathSpace.pl
* - * @version 5.0.0 + * @version 5.0.3 * */ public final class SyntaxTest { @@ -4671,4 +4671,64 @@ public void testSyn0304() { TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); Assertions.assertTrue(testResult); } + @Test + public void testSyn0305() { + TestCommonTools.testSynSettingsInit(); + boolean testResult = false; + String expStr = "2pi+3e"; + TestCommonTools.consolePrintTestSynStart(305, expStr); + Expression e = new Expression(expStr); + e.enableImpliedMultiplicationMode(); + boolean syn = e.checkSyntax(); + boolean reg = true; + if (syn == reg) + testResult = true; + TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); + Assertions.assertTrue(testResult); + } + @Test + public void testSyn0306() { + TestCommonTools.testSynSettingsInit(); + boolean testResult = false; + String expStr = "2pi+3e"; + TestCommonTools.consolePrintTestSynStart(306, expStr); + Expression e = new Expression(expStr); + e.disableImpliedMultiplicationMode(); + boolean syn = e.checkSyntax(); + boolean reg = false; + if (syn == reg) + testResult = true; + TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); + Assertions.assertTrue(testResult); + } + @Test + public void testSyn0307() { + TestCommonTools.testSynSettingsInit(); + boolean testResult = false; + String expStr = "2(3+4)5"; + TestCommonTools.consolePrintTestSynStart(307, expStr); + Expression e = new Expression(expStr); + e.enableImpliedMultiplicationMode(); + boolean syn = e.checkSyntax(); + boolean reg = true; + if (syn == reg) + testResult = true; + TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); + Assertions.assertTrue(testResult); + } + @Test + public void testSyn0308() { + TestCommonTools.testSynSettingsInit(); + boolean testResult = false; + String expStr = "2(3+4)5"; + TestCommonTools.consolePrintTestSynStart(308, expStr); + Expression e = new Expression(expStr); + e.disableImpliedMultiplicationMode(); + boolean syn = e.checkSyntax(); + boolean reg = false; + if (syn == reg) + testResult = true; + TestCommonTools.consolePrintTestSynEnd(syn, reg, testResult, e); + Assertions.assertTrue(testResult); + } }