ba07d9cd0e95e0702d02a4a3a1c8007a3e26313693477736ae1e71a6f00a702667d98756ab6eaba799706dea87095a2903f1ee3aadda950f31e966943d390a 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. 'use strict'
  2. var Mexp = require('./math_function.js')
  3. function inc(arr, val) {
  4. for (var i = 0; i < arr.length; i++) {
  5. arr[i] += val
  6. }
  7. return arr
  8. }
  9. var tokens = [
  10. { token: 'sin', show: 'sin', type: 0, value: Mexp.math.sin },
  11. { token: 'cos', show: 'cos', type: 0, value: Mexp.math.cos },
  12. { token: 'tan', show: 'tan', type: 0, value: Mexp.math.tan },
  13. { token: 'pi', show: '&pi;', type: 3, value: 'PI' },
  14. { token: '(', show: '(', type: 4, value: '(' },
  15. { token: ')', show: ')', type: 5, value: ')' },
  16. { token: 'P', show: 'P', type: 10, value: Mexp.math.P },
  17. { token: 'C', show: 'C', type: 10, value: Mexp.math.C },
  18. { token: ' ', show: ' ', type: 14, value: ' '.anchor },
  19. { token: 'asin', show: 'asin', type: 0, value: Mexp.math.asin },
  20. { token: 'acos', show: 'acos', type: 0, value: Mexp.math.acos },
  21. { token: 'atan', show: 'atan', type: 0, value: Mexp.math.atan },
  22. { token: '7', show: '7', type: 1, value: '7' },
  23. { token: '8', show: '8', type: 1, value: '8' },
  24. { token: '9', show: '9', type: 1, value: '9' },
  25. { token: 'int', show: 'Int', type: 0, value: Math.floor },
  26. { token: 'cosh', show: 'cosh', type: 0, value: Mexp.math.cosh },
  27. { token: 'acosh', show: 'acosh', type: 0, value: Mexp.math.acosh },
  28. { token: 'ln', show: ' ln', type: 0, value: Math.log },
  29. { token: '^', show: '^', type: 10, value: Math.pow },
  30. { token: 'root', show: 'root', type: 0, value: Math.sqrt },
  31. { token: '4', show: '4', type: 1, value: '4' },
  32. { token: '5', show: '5', type: 1, value: '5' },
  33. { token: '6', show: '6', type: 1, value: '6' },
  34. { token: '/', show: '&divide;', type: 2, value: Mexp.math.div },
  35. { token: '!', show: '!', type: 7, value: Mexp.math.fact },
  36. { token: 'tanh', show: 'tanh', type: 0, value: Mexp.math.tanh },
  37. { token: 'atanh', show: 'atanh', type: 0, value: Mexp.math.atanh },
  38. { token: 'Mod', show: ' Mod ', type: 2, value: Mexp.math.mod },
  39. { token: '1', show: '1', type: 1, value: '1' },
  40. { token: '2', show: '2', type: 1, value: '2' },
  41. { token: '3', show: '3', type: 1, value: '3' },
  42. { token: '*', show: '&times;', type: 2, value: Mexp.math.mul },
  43. { token: 'sinh', show: 'sinh', type: 0, value: Mexp.math.sinh },
  44. { token: 'asinh', show: 'asinh', type: 0, value: Mexp.math.asinh },
  45. { token: 'e', show: 'e', type: 3, value: 'E' },
  46. { token: 'log', show: ' log', type: 0, value: Mexp.math.log },
  47. { token: '0', show: '0', type: 1, value: '0' },
  48. { token: '.', show: '.', type: 6, value: '.' },
  49. { token: '+', show: '+', type: 9, value: Mexp.math.add },
  50. { token: '-', show: '-', type: 9, value: Mexp.math.sub },
  51. { token: ',', show: ',', type: 11, value: ',' },
  52. { token: 'Sigma', show: '&Sigma;', type: 12, value: Mexp.math.sigma },
  53. { token: 'n', show: 'n', type: 13, value: 'n' },
  54. { token: 'Pi', show: '&Pi;', type: 12, value: Mexp.math.Pi },
  55. { token: 'pow', show: 'pow', type: 8, value: Math.pow, numberOfArguments: 2 },
  56. { token: '&', show: '&', type: 9, value: Mexp.math.and },
  57. ]
  58. var preced = {
  59. 0: 11,
  60. 1: 0,
  61. 2: 3,
  62. 3: 0,
  63. 4: 0,
  64. 5: 0,
  65. 6: 0,
  66. 7: 11,
  67. 8: 11,
  68. 9: 1,
  69. 10: 10,
  70. 11: 0,
  71. 12: 11,
  72. 13: 0,
  73. 14: -1,
  74. 15: 11, // will be filtered after lexer
  75. } // stores precedence by types
  76. for (var i = 0; i < tokens.length; i++) {
  77. tokens[i].precedence = preced[tokens[i].type]
  78. }
  79. var type0 = {
  80. 0: true,
  81. 1: true,
  82. 3: true,
  83. 4: true,
  84. 6: true,
  85. 8: true,
  86. 9: true,
  87. 12: true,
  88. 13: true,
  89. 14: true,
  90. 15: true,
  91. } // type2:true,type4:true,type9:true,type11:true,type21:true,type22
  92. var type1 = {
  93. 0: true,
  94. 1: true,
  95. 2: true,
  96. 3: true,
  97. 4: true,
  98. 5: true,
  99. 6: true,
  100. 7: true,
  101. 8: true,
  102. 9: true,
  103. 10: true,
  104. 11: true,
  105. 12: true,
  106. 13: true,
  107. 15: true,
  108. } // type3:true,type5:true,type7:true,type23
  109. var type1Asterick = {
  110. 0: true,
  111. 3: true,
  112. 4: true,
  113. 8: true,
  114. 12: true,
  115. 13: true,
  116. 15: true,
  117. }
  118. var empty = {}
  119. var type3Asterick = {
  120. 0: true,
  121. 1: true,
  122. 3: true,
  123. 4: true,
  124. 6: true,
  125. 8: true,
  126. 12: true,
  127. 13: true,
  128. 15: true,
  129. } // type_5:true,type_7:true,type_23
  130. var type6 = {
  131. 1: true,
  132. }
  133. var newAr = [
  134. [],
  135. [
  136. '1',
  137. '2',
  138. '3',
  139. '7',
  140. '8',
  141. '9',
  142. '4',
  143. '5',
  144. '6',
  145. '+',
  146. '-',
  147. '*',
  148. '/',
  149. '(',
  150. ')',
  151. '^',
  152. '!',
  153. 'P',
  154. 'C',
  155. 'e',
  156. '0',
  157. '.',
  158. ',',
  159. 'n',
  160. ' ',
  161. '&',
  162. ],
  163. ['pi', 'ln', 'Pi'],
  164. ['sin', 'cos', 'tan', 'Del', 'int', 'Mod', 'log', 'pow'],
  165. ['asin', 'acos', 'atan', 'cosh', 'root', 'tanh', 'sinh'],
  166. ['acosh', 'atanh', 'asinh', 'Sigma'],
  167. ]
  168. function match(str1, str2, i, x) {
  169. for (var f = 0; f < x; f++) {
  170. if (str1[i + f] !== str2[f]) {
  171. return false
  172. }
  173. }
  174. return true
  175. }
  176. Mexp.tokenTypes = {
  177. FUNCTION_WITH_ONE_ARG: 0,
  178. NUMBER: 1,
  179. BINARY_OPERATOR_HIGH_PRECENDENCE: 2,
  180. CONSTANT: 3,
  181. OPENING_PARENTHESIS: 4,
  182. CLOSING_PARENTHESIS: 5,
  183. DECIMAL: 6,
  184. POSTFIX_FUNCTION_WITH_ONE_ARG: 7,
  185. FUNCTION_WITH_N_ARGS: 8,
  186. BINARY_OPERATOR_LOW_PRECENDENCE: 9,
  187. BINARY_OPERATOR_PERMUTATION: 10,
  188. COMMA: 11,
  189. EVALUATED_FUNCTION: 12,
  190. EVALUATED_FUNCTION_PARAMETER: 13,
  191. SPACE: 14,
  192. }
  193. /**
  194. 0 : function with syntax function_name(Maths_exp)
  195. 1 : numbers
  196. 2 : binary operators like * / Mod left associate and same precedence
  197. 3 : Math constant values like e,pi,Cruncher ans
  198. 4 : opening bracket
  199. 5 : closing bracket
  200. 6 : decimal
  201. 7 : function with syntax (Math_exp)function_name
  202. 8: function with syntax function_name(Math_exp1,Math_exp2)
  203. 9 : binary operator like +,-
  204. 10: binary operator like P C or ^
  205. 11: ,
  206. 12: function with , seperated three parameters and third parameter is a string that will be mexp string
  207. 13: variable of Sigma function
  208. */
  209. Mexp.addToken = function (newTokens) {
  210. for (var i = 0; i < newTokens.length; i++) {
  211. var x = newTokens[i].token.length
  212. var temp = -1
  213. if (newTokens[i].type === Mexp.tokenTypes.FUNCTION_WITH_N_ARGS && newTokens[i].numberOfArguments === undefined) {
  214. newTokens[i].numberOfArguments = 2
  215. }
  216. // newAr is a specially designed data structure index of 1d array = length of tokens
  217. newAr[x] = newAr[x] || []
  218. for (var y = 0; y < newAr[x].length; y++) {
  219. if (newTokens[i].token === newAr[x][y]) {
  220. temp = indexOfToken(newAr[x][y], tokens)
  221. break
  222. }
  223. }
  224. if (temp === -1) {
  225. tokens.push(newTokens[i])
  226. newTokens[i].precedence = preced[newTokens[i].type]
  227. if (newAr.length <= newTokens[i].token.length) {
  228. newAr[newTokens[i].token.length] = []
  229. }
  230. newAr[newTokens[i].token.length].push(newTokens[i].token)
  231. } else {
  232. // overwrite
  233. tokens[temp] = newTokens[i]
  234. newTokens[i].precedence = preced[newTokens[i].type]
  235. }
  236. }
  237. }
  238. function indexOfToken(key, tokens) {
  239. for (var search = 0; search < tokens.length; search++) {
  240. if (tokens[search].token === key) return search
  241. }
  242. return -1
  243. }
  244. function tokenize(string) {
  245. var nodes = []
  246. var length = string.length
  247. var key, x, y
  248. for (var i = 0; i < length; i++) {
  249. if (i < length - 1 && string[i] === ' ' && string[i + 1] === ' ') {
  250. continue
  251. }
  252. key = ''
  253. for (x = string.length - i > newAr.length - 2 ? newAr.length - 1 : string.length - i; x > 0; x--) {
  254. if (newAr[x] === undefined) continue
  255. for (y = 0; y < newAr[x].length; y++) {
  256. if (match(string, newAr[x][y], i, x)) {
  257. key = newAr[x][y]
  258. y = newAr[x].length
  259. x = 0
  260. }
  261. }
  262. }
  263. i += key.length - 1
  264. if (key === '') {
  265. throw new Mexp.Exception("Can't understand after " + string.slice(i))
  266. }
  267. nodes.push(tokens[indexOfToken(key, tokens)])
  268. }
  269. return nodes
  270. }
  271. var changeSignObj = {
  272. value: Mexp.math.changeSign,
  273. type: 0,
  274. pre: 21,
  275. show: '-',
  276. }
  277. var closingParObj = {
  278. value: ')',
  279. show: ')',
  280. type: 5,
  281. pre: 0,
  282. }
  283. var openingParObj = {
  284. value: '(',
  285. type: 4,
  286. pre: 0,
  287. show: '(',
  288. }
  289. Mexp.lex = function (inp, tokens) {
  290. 'use strict'
  291. var str = [openingParObj]
  292. var ptc = [] // Parenthesis to close at the beginning is after one token
  293. var inpStr = inp
  294. var allowed = type0
  295. var bracToClose = 0
  296. var asterick = empty
  297. var prevKey = ''
  298. var i
  299. if (typeof tokens !== 'undefined') {
  300. Mexp.addToken(tokens)
  301. }
  302. var obj = {}
  303. var nodes = tokenize(inpStr)
  304. for (i = 0; i < nodes.length; i++) {
  305. var node = nodes[i]
  306. if (node.type === 14) {
  307. if (
  308. i > 0 &&
  309. i < nodes.length - 1 &&
  310. nodes[i + 1].type === 1 &&
  311. (nodes[i - 1].type === 1 || nodes[i - 1].type === 6)
  312. ) {
  313. throw new Mexp.Exception('Unexpected Space')
  314. }
  315. continue
  316. }
  317. var cToken = node.token
  318. var cType = node.type
  319. var cEv = node.value
  320. var cPre = node.precedence
  321. var cShow = node.show
  322. var pre = str[str.length - 1]
  323. var j
  324. for (j = ptc.length; j--; ) {
  325. // loop over ptc
  326. if (ptc[j] === 0) {
  327. if ([0, 2, 3, 4, 5, 9, 11, 12, 13].indexOf(cType) !== -1) {
  328. if (allowed[cType] !== true) {
  329. throw new Mexp.Exception(cToken + ' is not allowed after ' + prevKey)
  330. }
  331. str.push(closingParObj)
  332. allowed = type1
  333. asterick = type3Asterick
  334. ptc.pop()
  335. }
  336. } else break
  337. }
  338. if (allowed[cType] !== true) {
  339. throw new Mexp.Exception(cToken + ' is not allowed after ' + prevKey)
  340. }
  341. if (asterick[cType] === true) {
  342. cType = 2
  343. cEv = Mexp.math.mul
  344. cShow = '&times;'
  345. cPre = 3
  346. i = i - 1
  347. }
  348. obj = {
  349. value: cEv,
  350. type: cType,
  351. pre: cPre,
  352. show: cShow,
  353. numberOfArguments: node.numberOfArguments,
  354. }
  355. if (cType === 0) {
  356. allowed = type0
  357. asterick = empty
  358. inc(ptc, 2)
  359. str.push(obj)
  360. if (nodes[i + 1].type !== 4) {
  361. str.push(openingParObj)
  362. ptc.push(2)
  363. }
  364. // bracToClose++
  365. } else if (cType === 1) {
  366. if (pre.type === 1) {
  367. pre.value += cEv
  368. inc(ptc, 1)
  369. } else {
  370. str.push(obj)
  371. }
  372. allowed = type1
  373. asterick = type1Asterick
  374. } else if (cType === 2) {
  375. allowed = type0
  376. asterick = empty
  377. inc(ptc, 2)
  378. str.push(obj)
  379. } else if (cType === 3) {
  380. // constant
  381. str.push(obj)
  382. allowed = type1
  383. asterick = type3Asterick
  384. } else if (cType === 4) {
  385. inc(ptc, 1)
  386. bracToClose++
  387. allowed = type0
  388. asterick = empty
  389. str.push(obj)
  390. } else if (cType === 5) {
  391. if (!bracToClose) {
  392. throw new Mexp.Exception('Closing parenthesis are more than opening one, wait What!!!')
  393. }
  394. bracToClose--
  395. allowed = type1
  396. asterick = type3Asterick
  397. str.push(obj)
  398. inc(ptc, 1)
  399. } else if (cType === 6) {
  400. if (pre.hasDec) {
  401. throw new Mexp.Exception('Two decimals are not allowed in one number')
  402. }
  403. if (pre.type !== 1) {
  404. pre = {
  405. value: 0,
  406. type: 1,
  407. pre: 0,
  408. } // pre needs to be changed as it will the last value now to be safe in later code
  409. str.push(pre)
  410. // inc(ptc, 1)
  411. }
  412. allowed = type6
  413. inc(ptc, 1)
  414. asterick = empty
  415. pre.value += cEv
  416. pre.hasDec = true
  417. } else if (cType === 7) {
  418. allowed = type1
  419. asterick = type3Asterick
  420. inc(ptc, 1)
  421. str.push(obj)
  422. }
  423. if (cType === 8) {
  424. allowed = type0
  425. asterick = empty
  426. inc(ptc, node.numberOfArguments + 2)
  427. str.push(obj)
  428. // str.push(openingParObj)
  429. if (nodes[i + 1].type !== 4) {
  430. str.push(openingParObj)
  431. ptc.push(node.numberOfArguments + 2)
  432. }
  433. } else if (cType === 9) {
  434. if (pre.type === 9) {
  435. if (pre.value === Mexp.math.add) {
  436. pre.value = cEv
  437. pre.show = cShow
  438. inc(ptc, 1)
  439. } else if (pre.value === Mexp.math.sub && cShow === '-') {
  440. pre.value = Mexp.math.add
  441. pre.show = '+'
  442. inc(ptc, 1)
  443. }
  444. } else if (pre.type !== 5 && pre.type !== 7 && pre.type !== 1 && pre.type !== 3 && pre.type !== 13) {
  445. // changesign only when negative is found
  446. if (cToken === '-') {
  447. // do nothing for + token
  448. // don't add with the above if statement as that will run the else statement of parent if on Ctoken +
  449. allowed = type0
  450. asterick = empty
  451. inc(ptc, 2).push(2)
  452. str.push(changeSignObj)
  453. str.push(openingParObj)
  454. }
  455. } else {
  456. str.push(obj)
  457. inc(ptc, 2)
  458. }
  459. allowed = type0
  460. asterick = empty
  461. } else if (cType === 10) {
  462. allowed = type0
  463. asterick = empty
  464. inc(ptc, 2)
  465. str.push(obj)
  466. } else if (cType === 11) {
  467. allowed = type0
  468. asterick = empty
  469. str.push(obj)
  470. } else if (cType === 12) {
  471. allowed = type0
  472. asterick = empty
  473. inc(ptc, 6)
  474. str.push(obj)
  475. if (nodes[i + 1].type !== 4) {
  476. str.push(openingParObj)
  477. ptc.push(6)
  478. }
  479. } else if (cType === 13) {
  480. allowed = type1
  481. asterick = type3Asterick
  482. str.push(obj)
  483. }
  484. inc(ptc, -1)
  485. prevKey = cToken
  486. }
  487. for (j = ptc.length; j--; ) {
  488. // loop over ptc
  489. str.push(closingParObj)
  490. }
  491. if (allowed[5] !== true) {
  492. throw new Mexp.Exception('complete the expression')
  493. }
  494. while (bracToClose--) {
  495. str.push(closingParObj)
  496. }
  497. str.push(closingParObj)
  498. // console.log(str);
  499. return new Mexp(str)
  500. }
  501. module.exports = Mexp