Advertisement
IzhanVarsky

Untitled

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