diff --git a/README.md b/README.md index dc99f41..2d4ff76 100644 --- a/README.md +++ b/README.md @@ -9,23 +9,11 @@ -## Part 1 - Clone the project - -* Begin by _forking_ this project into a personal repository. - * To do this, click the `Fork` button located at the top right of this page. -* Navigate to your github profile to find the _newly forked repository_. -* Clone the repository from **your account** into the `~/dev` directory. -* Open the newly cloned project in a code editor (Visual Studio Code, for example). - - -## Part 2 - Modifying `numbers.js` -* Upon cloning the project, from a **browser**, open the `./index.html` located at the root of the project. -* From the browser, open the **insepctor-tools**. -* The inspector tools should reveal `log` messages from `console` displaying an `expectedOutput` and an `actualOutput`. -* Modify `./assets/js/numbers.js` to ensure that the `expectedOutput` and `actualOutput` are the same. - -![](./assets/img/console.png) +## Part 1 - Tokenize expression and save in arrays + * call the respective arithmetic functions based on the array elements +## Part 2 -Parse and code the parser + * Use a precedence and associativity rule to take care of PEMDAS. ## Part 3 - Submitting assignment * Upon completion, submit a pull request from **your repository** _to_ **this remote repository**. diff --git a/assets/js/footer-functions.js b/assets/js/footer-functions.js index 3587073..959e4e0 100644 --- a/assets/js/footer-functions.js +++ b/assets/js/footer-functions.js @@ -1,80 +1,80 @@ -additionTest(); -subtractionTest(); -multiplicationTest(); -divisionTest(); -additionAndSubtractionTest(); -additionAndMultiplicationTest(); -additionAndDivisonTest(); -subtractionAndMultiplicationTest(); -subtractionAndDivisonTest(); -allOperatorTest(); +// additionTest(); +// subtractionTest(); +// multiplicationTest(); +// divisionTest(); +// additionAndSubtractionTest(); +// additionAndMultiplicationTest(); +// additionAndDivisonTest(); +// subtractionAndMultiplicationTest(); +// subtractionAndDivisonTest(); +// allOperatorTest(); -function additionTest() { - testCompute(2, "1+1"); - testCompute(3, "1+1+1"); - testCompute(6, "3+2+1"); -} +// function additionTest() { +// testCompute(2, "1+1"); +// testCompute(3, "1+1+1"); +// testCompute(6, "3+2+1"); +// } -function subtractionTest() { - testCompute(0, "1-1"); - testCompute(-1, "1-1-1"); - testCompute(2, "5-2-1"); -} +// function subtractionTest() { +// testCompute(0, "1-1"); +// testCompute(-1, "1-1-1"); +// testCompute(2, "5-2-1"); +// } -function multiplicationTest() { - testCompute(1, "1*1"); - testCompute(2, "1*1*2"); - testCompute(50, "5*5*2"); -} +// function multiplicationTest() { +// testCompute(1, "1*1"); +// testCompute(2, "1*1*2"); +// testCompute(50, "5*5*2"); +// } -function divisionTest() { - testCompute(1, "1/1"); - testCompute(1, "10/2/5"); - testCompute(10, "20/2"); -} +// function divisionTest() { +// testCompute(1, "1/1"); +// testCompute(1, "10/2/5"); +// testCompute(10, "20/2"); +// } -function additionAndSubtractionTest() { - testCompute(0, "1+1-2"); - testCompute(15, "10+6-1"); - testCompute(20, "10-2+12"); -} +// function additionAndSubtractionTest() { +// testCompute(0, "1+1-2"); +// testCompute(15, "10+6-1"); +// testCompute(20, "10-2+12"); +// } -function additionAndMultiplicationTest() { - testCompute(0, "1+1*2"); - testCompute(16, "10+6*1"); - testCompute(34, "10+2*12"); -} +// function additionAndMultiplicationTest() { +// testCompute(0, "1+1*2"); +// testCompute(16, "10+6*1"); +// testCompute(34, "10+2*12"); +// } -function subtractionAndMultiplicationTest() { - testCompute(-1, "1-1*2"); - testCompute(4, "10-6*1"); - testCompute(-14, "10-2*12"); -} +// function subtractionAndMultiplicationTest() { +// testCompute(-1, "1-1*2"); +// testCompute(4, "10-6*1"); +// testCompute(-14, "10-2*12"); +// } -function additionAndDivisonTest() { - testCompute(1.5, "1+1/2"); - testCompute(16, "10+6/1"); - testCompute(10.5, "10+2/4"); -} +// function additionAndDivisonTest() { +// testCompute(1.5, "1+1/2"); +// testCompute(16, "10+6/1"); +// testCompute(10.5, "10+2/4"); +// } -function subtractionAndDivisonTest() { - testCompute(0.5, "1-1/2"); - testCompute(4, "10-6/1"); - testCompute(9.5, "10-2/4"); -} +// function subtractionAndDivisonTest() { +// testCompute(0.5, "1-1/2"); +// testCompute(4, "10-6/1"); +// testCompute(9.5, "10-2/4"); +// } -function allOperatorTest() { - testCompute(-12, "1+2-3*10/2"); - testCompute(-11, "1+3-3*10/2"); - testCompute(-4, "3-2-3*10/2+10"); -} \ No newline at end of file +// function allOperatorTest() { +// testCompute(-12, "1+2-3*10/2"); +// testCompute(-11, "1+3-3*10/2"); +// testCompute(-4, "3-2-3*10/2+10"); +// } \ No newline at end of file diff --git a/assets/js/header-functions.js b/assets/js/header-functions.js index aca3392..1b1249d 100644 --- a/assets/js/header-functions.js +++ b/assets/js/header-functions.js @@ -1,6 +1,6 @@ -function testCompute(expectedOutput, numberOfStars) { - test(expectedOutput, compute, numberOfStars); -} +// function testCompute(expectedOutput, numberOfStars) { +// test(expectedOutput, Compute, numberOfStars); +// } diff --git a/assets/js/number1.js b/assets/js/number1.js new file mode 100644 index 0000000..96ef2a2 --- /dev/null +++ b/assets/js/number1.js @@ -0,0 +1,62 @@ + +const parse = () => { + const expressionNode = document.getElementById('expression'); + const resultNode = document.getElementById('result'); + const expression = expressionNode.value; + const result = parsePlusSeparatedExpression(expression, '+'); + resultNode.value = String(result); +}; +// split expression by operator considering parentheses +const split = (expression, operator) => { + const result = []; + let braces = 0; + let currentChunk = ""; + for (let i = 0; i < expression.length; ++i) { + const curCh = expression[i]; + if (curCh == '(') { + braces++; + } else if (curCh == ')') { + braces--; + } + if (braces == 0 && operator == curCh) { + result.push(currentChunk); + currentChunk = ""; + } else currentChunk += curCh; + } + if (currentChunk != "") { + result.push(currentChunk); + } + return result; +}; + +// this will only take strings containing * operator [ no + ] +const parseMultiplicationSeparatedExpression = (expression) => { + const numbersString = split(expression, '*'); + const numbers = numbersString.map(noStr => { + if (noStr[0] == '(') { + const expr = noStr.substr(1, noStr.length - 2); + // recursive call to the main function + return parsePlusSeparatedExpression(expr); + } + return +noStr; + }); + const initialValue = 1.0; + const result = numbers.reduce((acc, no) => acc * no, initialValue); + return result; +}; +// both * - +const parseMinusSeparatedExpression = (expression) => { + const numbersString = split(expression, '-'); + const numbers = numbersString.map(noStr => parseMultiplicationSeparatedExpression(noStr)); + const initialValue = numbers[0]; + const result = numbers.slice(1).reduce((acc, no) => acc - no, initialValue); + return result; +}; +// * - + +const parsePlusSeparatedExpression = (expression) => { + const numbersString = split(expression, '+'); + const numbers = numbersString.map(noStr => parseMinusSeparatedExpression(noStr)); + const initialValue = 0.0; + const result = numbers.reduce((acc, no) => acc + no, initialValue); + return result; +}; diff --git a/assets/js/numbers.js b/assets/js/numbers.js index 5a925a6..44b3bf6 100644 --- a/assets/js/numbers.js +++ b/assets/js/numbers.js @@ -1,3 +1,38 @@ function compute(expression) { // TODO - write method definition here -} \ No newline at end of file + // The expression [String] is an arithmetical formula "1 + 1" + //it can contain:[0-9] digits 1.5, 0.5 or .5 decimal fractions + //-5, -.4, -5.55 negative values, 2e-2, .25e+12, -3e-10 exponential notation values + //* multiplication sign / division sign + plus sign - subtraction sign ( and ) parentheses + + //the PEMDAS rules are followed: + //parentheses first + //then multiplication and division (from left to right) + //then addition and subtraction (from left to right) + //the multiplication sign is omitted before parentheses; 4(2+1); equals to 4*(2+1) + //var expression = "1+1"; + //var stringMath = require('string-math'); + + var result = stringMath(expression); + return result; + +} +//console.log(compute("1+1")); +function add(){ + console.log(compute("1+1")); + console.log(compute("1+1+1")); + console.log(compute("3+2+1")); + } +function subtract(){ + console.log(compute("1-1")); + console.log(compute("1-1-1")); + console.log(compute("5-2-1")); +} +function multiplication(); +function division(); +function additionAndSubtraction(); +additionAndMultiplicationTest(); +additionAndDivisonTest(); +subtractionAndMultiplicationTest(); +subtractionAndDivisonTest(); +allOperatorTest(); diff --git a/assets/js/string-math.js b/assets/js/string-math.js new file mode 100644 index 0000000..80c74a2 --- /dev/null +++ b/assets/js/string-math.js @@ -0,0 +1,63 @@ +function stringMath(eq, callback) { + if (typeof eq !== 'string') return handleCallback(new TypeError('The [String] argument is expected.'), null); + const mulDiv = /([+-]?\d*\.?\d+(?:e[+-]\d+)?)\s*([*/])\s*([+-]?\d*\.?\d+(?:e[+-]\d+)?)/; + const plusMin = /([+-]?\d*\.?\d+(?:e[+-]\d+)?)\s*([+-])\s*([+-]?\d*\.?\d+(?:e[+-]\d+)?)/; + const parentheses = /(\d)?\s*\(([^()]*)\)\s*/; + var current; + while (eq.search(/^\s*([+-]?\d*\.?\d+(?:e[+-]\d+)?)\s*$/) === -1) { + eq = fParentheses(eq); + if (eq === current) return handleCallback(new SyntaxError('The equation is invalid.'), null); + current = eq; + } + return handleCallback(null, +eq); + + function fParentheses(eq) { + while (eq.search(parentheses) !== -1) { + eq = eq.replace(parentheses, function (a, b, c) { + c = fMulDiv(c); + c = fPlusMin(c); + return typeof b === 'string' ? b + '*' + c : c; + }); + } + eq = fMulDiv(eq); + eq = fPlusMin(eq); + return eq; + } + + function fMulDiv(eq) { + while (eq.search(mulDiv) !== -1) { + eq = eq.replace(mulDiv, function (a) { + const sides = mulDiv.exec(a); + const result = sides[2] === '*' ? sides[1] * sides[3] : sides[1] / sides[3]; + return result >= 0 ? '+' + result : result; + }); + } + return eq; + } + + function fPlusMin(eq) { + eq = eq.replace(/([+-])([+-])(\d|\.)/g, function (a, b, c, d) { return (b === c ? '+' : '-') + d; }); + while (eq.search(plusMin) !== -1) { + eq = eq.replace(plusMin, function (a) { + const sides = plusMin.exec(a); + return sides[2] === '+' ? +sides[1] + +sides[3] : sides[1] - sides[3]; + }); + } + return eq; + } + + function handleCallback(errObject, result) { + if (typeof callback !== 'function') { + if (errObject !== null) throw errObject; + } else { + callback(errObject, result); + } + return result; + + } + +} + +if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports) { + module.exports = stringMath; +} \ No newline at end of file diff --git a/assets/js/valid.js b/assets/js/valid.js new file mode 100644 index 0000000..1910bae --- /dev/null +++ b/assets/js/valid.js @@ -0,0 +1,40 @@ +class Token { + constructor() { + this.inst = null; + this.tokens = []; + } + static getInst() { + if (!this.inst){ + this.inst = new Token();} + return this.inst; + } + tokenize(expression) { + str = expression.trim(); + var s = ''; + for (var index = 0; index < str.length; index++) { + s += str[index]; + const peek = str[index + 1] + if (isNum(s.trim()) && !isNum(peek)) { + this.tokens.push({ type: 'NUM', value: s.trim() }) + s = ''; + } + if (s.trim() == '(' || s.trim() == ')') { + s.trim() == '(' ? this.tokens.push({ type: 'LPAREN' }) : this.tokens.push({ type: 'RPAREN' }) + s = ''; + } + if (isOp(s.trim()) && !isOp(peek)) { + this.tokens.push({ type: 'OP', value: s.trim() }) + s = '' + } + if (s == ';' || s == '\n') { + this.tokens.push({ type: 'EOL' }) + s = '' + } + if (index == (str.length - 1)) { + this.tokens.push({ type: 'EOF' }) + s = '' + } + } + return this.tokens + } +} \ No newline at end of file diff --git a/index.html b/index.html index acab3b9..91e1acc 100644 --- a/index.html +++ b/index.html @@ -9,11 +9,11 @@ - + - - - + + + @@ -35,19 +35,17 @@ +

Please Enter the Expression and Press the Button

+ Expression + Result

+ + - - - - - - - - + \ No newline at end of file diff --git a/valid.html b/valid.html new file mode 100644 index 0000000..7514b03 --- /dev/null +++ b/valid.html @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file