IzhanVarsky

Untitled

Apr 13th, 2019
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. "use strict";
  2.  
  3. let ind = 0;
  4. let expr = "";
  5.  
  6. function MyException(message) {
  7.     this.message = message
  8. }
  9.  
  10. function getFullByRegExp(reg) {
  11.     // /\d/ - digits
  12.     // /[A-Za-z]/ - alphabetic
  13.     let res = "";
  14.     while (ind < expr.length && reg.test(expr[ind])) {
  15.         res += expr[ind];
  16.         ind++;
  17.     }
  18.     return res;
  19. }
  20.  
  21. function skipWhiteSpaces() {
  22.     while (ind < expr.length && /\s/.test(expr[ind])) {
  23.         ind++;
  24.     }
  25. }
  26.  
  27. function checkDigits(s) {
  28.     let pos = 0;
  29.     while (true) {
  30.         if (pos >= s.length) return true;
  31.         if (/\d/.test(s[pos])) {
  32.             pos++;
  33.         } else {
  34.             return false;
  35.         }
  36.     }
  37. }
  38.  
  39. function readBrackets() {
  40.     ind++;
  41.     let operation = getOperation();
  42.     // console.log("operation " + operation);
  43.     if (!OPERATIONS.has(operation)) {
  44.         throw new MyException("Unknown operation: " + operation);
  45.     }
  46.     let op = getOperands();
  47.     // console.log("operands " + op);
  48.     if (OPERATIONS.get(operation)[1] !== op.length) {
  49.         throw new MyException("Operation: " + operation + ". Expected " +
  50.             OPERATIONS.get(operation)[1] + "arguments. Found: " + op);
  51.     }
  52.     // console.log("OPERATIONS.get(operation)[0]: " + OPERATIONS.get(operation)[0]);
  53.     // console.log("op[0]: " + op[0]);
  54.     // console.log("op[1]: " + op[1]);
  55.     switch (operation) {
  56.         case "+": {
  57.             return new Add(op[0], op[1]);
  58.         }
  59.         case "-": {
  60.             return new Subtract(op[0], op[1]);
  61.         }
  62.         case "*": {
  63.             return new Multiply(op[0], op[1]);
  64.         }
  65.         case "/": {
  66.             return new Divide(op[0], op[1]);
  67.         }
  68.     }
  69.     // return (OPERATIONS.get(operation)[0]).apply(op); ????
  70. }
  71.  
  72. function getOperation() {
  73.     skipWhiteSpaces();
  74.     return getFullByRegExp(/\S/);
  75. }
  76.  
  77. function getOperands() {
  78.     let curStack = []; // аргументы - тоже функции (инвариант)
  79.     while (true) {
  80.         skipWhiteSpaces();
  81.         let token = "";
  82.         while (ind < expr.length && /\S/.test(expr[ind]) && !/[()]/.test(expr[ind])) {
  83.             token += expr[ind];
  84.             ind++;
  85.         }
  86.         skipWhiteSpaces();
  87.         // let token = getFullByRegExp(/\S[^()]/); ????
  88.         if (checkDigits(token)) {
  89.             curStack.push(new Const(parseInt(token, 10)));
  90.         } else if (token.length !== 0) {
  91.             if (!VARIABLES.has(token)) {
  92.                 throw new MyException("Unknown variable:" + token);
  93.             }
  94.             curStack.push(new Variable(token));
  95.         } else if (expr[ind] === '(') {
  96.             curStack.push(readBrackets());
  97.         } else if (expr[ind] === ')') {
  98.             ind++;
  99.             return curStack;
  100.         } else {
  101.             throw new MyException("Unexpected exception." + "Token: " + token + "Pos: " + ind + "Char: " + expr[ind]);
  102.         }
  103.     }
  104. }
  105.  
  106. function parsePrefix(str) {
  107.     expr = str;
  108.     ind = 0;
  109.     skipWhiteSpaces();
  110.     if (expr[ind] === '(') {
  111.         let res = readBrackets();
  112.         skipWhiteSpaces();
  113.         if (ind < expr.length) {
  114.             throw new MyException("Cannot parse next. Stopped on position: " + ind);
  115.         }
  116.         return res;
  117.     }
  118.     let token = getFullByRegExp(/\S/);
  119.     skipWhiteSpaces();
  120.     if (ind < expr.length) {
  121.         throw new MyException("Cannot parse next. Stopped on position: " + ind);
  122.     }
  123.     if (checkDigits(token)) {
  124.         return new Const(parseInt(token, 10));
  125.     } else if (token.length !== 0) {
  126.         if (!VARIABLES.has(token)) {
  127.             throw new MyException("Unknown variable:" + token);
  128.         }
  129.         return new Variable(token);
  130.     }
  131.     throw new MyException("Cannot start parse. Stopped on position: " + ind);
  132. }
  133.  
  134. function newOperation(action, symbol) {
  135.     function Operation(...args) {
  136.         this.operands = args;
  137.     }
  138.  
  139.     Operation.prototype.toString = function () {
  140.         return this.operands.join(" ") + " " + symbol;
  141.     };
  142.     Operation.prototype.prefix = function () {
  143.         return "(" + symbol + " " + this.operands.map(value => value.prefix()).join(" ") + ")";
  144.     };
  145.     Operation.prototype.evaluate = function (...args) {
  146.         return action(...this.operands.map(operand => operand.evaluate(...args)));
  147.     };
  148.  
  149.     return Operation;
  150. }
  151.  
  152. function Const(x) {
  153.     this.value = x;
  154. }
  155.  
  156. Const.prototype.toString = function () {
  157.     return this.value.toString();
  158. };
  159. Const.prototype.evaluate = function () {
  160.     return this.value;
  161. };
  162. Const.prototype.prefix = Const.prototype.toString;
  163.  
  164. function Variable(s) {
  165.     this.name = s;
  166.     this.index = VARIABLES.get(s);
  167. }
  168.  
  169. Variable.prototype.toString = function () {
  170.     return this.name;
  171. };
  172. Variable.prototype.evaluate = function (...args) {
  173.     return args[this.index];
  174. };
  175. Variable.prototype.prefix = Variable.prototype.toString;
  176.  
  177. const Add = newOperation((a, b) => a + b, "+");
  178. const Subtract = newOperation((a, b) => a - b, "-");
  179. const Multiply = newOperation((a, b) => a * b, "*");
  180. const Divide = newOperation((a, b) => a / b, "/");
  181. const Negate = newOperation(a => -a, "negate");
  182. const Min3 = newOperation((a, b, c) => Math.min(a, b, c), "min3");
  183. const Max5 = newOperation((a, b, c, d, e) => Math.max(a, b, c, d, e), "max5");
  184.  
  185. const OPERATIONS = new Map([
  186.     ['+', [Add, 2]],
  187.     ['-', [Subtract, 2]],
  188.     ['*', [Multiply, 2]],
  189.     ['/', [Divide, 2]],
  190.     ['negate', [Negate, 1]],
  191.     ['min3', [Min3, 3]],
  192.     ['max5', [Max5, 5]]
  193. ]);
  194.  
  195. const CONSTANTS = new Map([
  196.     ['one', 1],
  197.     ['two', 2],
  198.     ['pi', Math.PI],
  199.     ['e', Math.E]
  200. ]);
  201.  
  202. const VARIABLES = new Map([
  203.     ["x", 0],
  204.     ["y", 1],
  205.     ["z", 2]
  206. ]);
Advertisement
Add Comment
Please, Sign In to add comment