Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- var Calc = function() {
- 'use strict';
- this.vars = {
- pi: Math.PI.toString()
- };
- };
- Calc.prototype.evaluate = function(expression) {
- 'use strict';
- // Trigger final instruction to execute at end.
- expression += ' ';
- // Loop Variables
- var length = expression.length,
- iter,
- char,
- type;
- // Flags
- var flag_number = false,
- flag_float = false,
- flag_keyword = false,
- flag_operator = false,
- flag_operator_waiting = false,
- flag_brackets = 0,
- flag_var = false,
- flag_var_maybe = false,
- flag_var_name = '',
- flag_math = false,
- flag_math_op = '',
- flag_num_consecutive = null,
- flag_equals = false,
- flag_bracket = false;
- // Parser Variables
- var buffer = '',
- total = 0,
- cur_operator = null,
- buffer_parsed = 0,
- prev_num = null,
- bIndex,
- bDepth = 0;
- // Math Functions
- var stdOps = ['log', 'tan'],
- customOps = {
- fact: function(value) {
- var iter,
- multiplier;
- for(multiplier = value - 1; multiplier > 0; --multiplier) {
- value *= multiplier;
- }
- return value;
- },
- sin: function(value) {
- return Math.sin(value * Math.PI / 180);
- },
- cos: function(value) {
- return Math.cos(value * Math.PI / 180);
- }
- };
- // Keyword Functions
- // Helper Functions
- function isAlpha(char) {
- return 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.indexOf(char) !== -1;
- }
- function isNumeric(char) {
- return '1234567890.,'.indexOf(char) !== -1;
- }
- function isSpecial(char) {
- return '+-*/^='.indexOf(char) !== -1;
- }
- function applyOperator(left, right, operator) {
- // Addition
- if(operator === '+') {
- return left + right;
- }
- // Subtraction
- if(operator === '-') {
- return left - right;
- }
- // Division
- if(operator === '/') {
- return left / right;
- }
- // Multiplication
- if(operator === '*') {
- return left * right;
- }
- if(operator === '^') {
- return Math.pow(left, right);
- }
- return null;
- }
- for(iter = 0; iter < length; ++iter) {
- char = expression.charAt(iter);
- if(flag_bracket) {
- if(char === '(') {
- bDepth++;
- }
- if(char === ')') {
- bDepth--;
- }
- if(bDepth === 0) {
- //flag_bracket = false;
- buffer = this.evaluate(expression.substring(bIndex + 1, iter));
- if(buffer === false) {
- return false;
- }
- // Script parses a string, not integers, so
- // conversion to string is necessary.
- buffer = buffer.toString();
- flag_number = true;
- // Check for float
- flag_float = buffer.indexOf('.') !== -1;
- } else {
- continue;
- }
- }
- // Are we parsing a number
- if(flag_number) {
- // The number has finished
- if(!isNumeric(char)) {
- if(isSpecial(buffer) && !isSpecial(char)) {
- flag_number = false;
- flag_operator = false;
- }
- // Is it a float?
- if(flag_float) {
- buffer_parsed = parseFloat(buffer, 10);
- } else {
- buffer_parsed = parseInt(buffer, 10);
- }
- // Is there an operator waiting?
- if(flag_operator_waiting) {
- // We are setting a variable
- if(flag_var && flag_equals) {
- this.vars[flag_var_name] = buffer;
- flag_var = false;
- flag_var_name = '';
- } else {
- total = applyOperator(total, buffer_parsed, cur_operator);
- // console.log(total);
- // Turns out, we're not setting a variable, we were just referencing it.
- if(flag_var) {
- if(flag_var_name in this.vars) {
- buffer = this.vars[flag_var_name];
- flag_var = false;
- flag_var_name = '';
- flag_number = true;
- if(buffer.indexOf('.') !== -1) {
- flag_float = true;
- }
- iter--
- continue;
- } else {
- console.log("Invalid variable '" + flag_var_name + "'");
- return false;
- }
- }
- // Reset flags
- flag_number = false;
- flag_float = false;
- flag_operator_waiting = false;
- // Unkown operator
- if(total === null) {
- process.stdout.write("Unrecognised operator '" + cur_operator + "'");
- break;
- }
- }
- // Reset current operator
- cur_operator = '';
- } else {
- // Is a mathematical function waiting? (sin, cos, tan etc)
- if(flag_math) {
- flag_math = false;
- buffer = flag_math_op(buffer_parsed).toString();
- // Check if float
- if(buffer.indexOf('.') !== -1) {
- flag_float = true;
- }
- iter--;
- continue;
- }
- // Else it's just a number, function call, or variable at the beginning of the expression
- total = buffer_parsed;
- flag_number = false;
- }
- buffer = '';
- cur_operator = '';
- } else {
- // Check for float
- if(char === '.') {
- flag_float = true;
- }
- // Allow for commas
- if(char === ',') {
- continue;
- }
- buffer += char;
- continue;
- }
- }
- if(flag_keyword) {
- if(!isAlpha(char)) {
- flag_keyword = false;
- // Case insensitivity
- buffer = buffer.toLocaleLowerCase(buffer);
- if(buffer === 'exit') { // exit command
- console.log('Goodbye!');
- process.exit();
- } else if(buffer === 'set') { // Setting variable
- flag_var = true;
- } else {
- // Standard Math.[sin|cos|tan|log] operations
- if(stdOps.indexOf(buffer) !== -1) {
- flag_math = true;
- flag_math_op = Math[buffer];
- }
- // Custom operations: fact (factorial)
- if(buffer in customOps) {
- flag_math = true;
- flag_math_op = customOps[buffer];
- }
- // If not mathematical function, it must be a variable
- if(!flag_math) {
- // Are we setting a variable?
- if(flag_var && flag_var_name === '') {
- flag_var_name = buffer;
- } else {
- // We may be setting a variable
- flag_var_maybe = true;
- flag_var_name = buffer;
- // We may be referencing a variable, too.
- if(buffer in this.vars) {
- buffer = this.vars[buffer];
- flag_number = true;
- // Check if variable is float
- if(buffer.indexOf('.') !== -1) {
- flag_float = true;
- }
- --iter;
- //console.log(buffer);
- continue;
- }
- }
- }
- }
- buffer = '';
- } else {
- buffer += char;
- continue;
- }
- }
- // Are we parsing an operator?
- if(flag_operator) {
- // Are we ending an operator?
- if(!isSpecial(char) || (flag_equals && (buffer === '-' || buffer === '+')) || char === '-' || char === '+') {
- // reset flags
- flag_operator = false;
- cur_operator = buffer;
- if(flag_equals && (buffer === '-' || buffer === '+')) {
- flag_number = true;
- continue;
- }
- // reset buffer
- buffer = '';
- flag_operator_waiting = true;
- if(char === '-' || char === '+') {
- flag_number = true;
- buffer += char;
- continue;
- }
- } else {
- buffer += char;
- continue;
- }
- }
- // A number has started
- if(isNumeric(char)) {
- flag_number = true;
- buffer += char;
- continue;
- }
- // A keyword, variable or function has started
- if(isAlpha(char)) {
- flag_keyword = true;
- buffer += char;
- continue;
- }
- // An operator has started
- if(isSpecial(char)) {
- if(char === '=') {
- //console.log(char);
- flag_var_maybe = false;
- flag_var = true;
- flag_equals = true;
- continue;
- } else {
- if((char === '-' || char === '+') && (flag_operator_waiting || flag_math)) {
- buffer += char;
- flag_number = true;
- continue;
- } else {
- flag_operator = true;
- buffer += char;
- continue;
- }
- }
- }
- // Parse parentheses
- if(char === '(') {
- // Increment bracket depth
- ++bDepth;
- bIndex = iter;
- flag_bracket = true;
- continue;
- /*if(bIndex !== -1) {
- // extract and independtly evaluate this sub-expression, in a recursive fashion
- buffer = this.evaluate(expression.substring(iter + 1, bIndex));
- if(buffer === false) {
- return false;
- }
- buffer = buffer.toString();
- flag_number = true;
- flag_float = buffer.indexOf('.') !== -1;
- iter = bIndex;
- continue;
- } else {
- console.log("Invalid bracket syntax");
- return false;
- }*/
- }
- if(char === ')' && flag_bracket) {
- flag_bracket = false;
- continue;
- }
- if(char !== ' ' && char !== "\n" && char !== '\r') {
- console.log("Unexpected character '" + char + "'");
- return false;
- }
- }
- // We are setting a variable
- if(flag_var || flag_var_maybe) {
- if(!flag_equals) {
- if(!(flag_var_name in this.vars)) {
- console.log("Invalid variable '" + flag_var_name + "'");
- return false;
- }
- }
- this.vars[flag_var_name] = total.toString();
- }
- if(flag_bracket) {
- console.log("Invalid bracket syntax");
- return false;
- }
- return total;
- };
- var calc = new Calc();
- process.stdin.resume();
- process.stdin.setEncoding('utf8');
- process.stdin.on('data', function(expression) {
- var result = calc.evaluate(expression);
- if(result !== false) {
- console.log(result)
- }
- process.stdout.write("> ");
- });
- console.log("Welcome to calc.js:");
- process.stdout.write("> ");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement