lexer.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. var Mexp=require('./math_function.js');
  2. function inc(arr,val){
  3. for(var i=0;i<arr.length;i++)
  4. arr[i]+=val;
  5. return arr;
  6. }
  7. var token=['sin','cos','tan','pi','(',')','P','C',
  8. 'asin','acos','atan','7','8','9','int',
  9. 'cosh','acosh','ln','^','root','4','5','6','/','!',
  10. 'tanh','atanh','Mod','1','2','3','*',
  11. 'sinh','asinh','e','log','0','.','+','-',',','Sigma','n','Pi','pow'];
  12. var show=['sin','cos','tan','&pi;','(',')','P','C',
  13. 'asin','acos','atan','7','8','9','Int',
  14. 'cosh','acosh',' ln','^','root','4','5','6','&divide;','!',
  15. 'tanh','atanh',' Mod ','1','2','3','&times;',
  16. 'sinh','asinh','e',' log','0','.','+','-',',','&Sigma;','n','&Pi;','pow'];
  17. var eva=[Mexp.math.sin,Mexp.math.cos,Mexp.math.tan,'PI','(',')',Mexp.math.P,Mexp.math.C,
  18. Mexp.math.asin,Mexp.math.acos,Mexp.math.atan,'7','8','9',Math.floor,
  19. Mexp.math.cosh,Mexp.math.acosh,Math.log,Math.pow,Math.sqrt,'4','5','6',Mexp.math.div,Mexp.math.fact,
  20. Mexp.math.tanh,Mexp.math.atanh,Mexp.math.mod,'1','2','3',Mexp.math.mul,
  21. Mexp.math.sinh,Mexp.math.asinh,'E',Mexp.math.log,'0','.',Mexp.math.add,Mexp.math.sub,',',Mexp.math.sigma,'n',Mexp.math.Pi,Math.pow];
  22. var preced={0:11,1:0,2:3,3:0,4:0,5:0,6:0,7:11,8:11,9:1,10:10,11:0,12:11,13:0};
  23. var type=[0,0,0,3,4,5,10,10,
  24. 0,0,0,1,1,1,0,
  25. 0,0,0,10,0,1,1,1,2,7,
  26. 0,0,2,1,1,1,2,
  27. 0,0,3,0,1,6,9,9,11,12,13,12,8];
  28. /*
  29. 0 : function with syntax function_name(Maths_exp)
  30. 1 : numbers
  31. 2 : binary operators like * / Mod left associate and same precedence
  32. 3 : Math constant values like e,pi,Cruncher ans
  33. 4 : opening bracket
  34. 5 : closing bracket
  35. 6 : decimal
  36. 7 : function with syntax (Math_exp)function_name
  37. 8: function with syntax function_name(Math_exp1,Math_exp2)
  38. 9 : binary operator like +,-
  39. 10: binary operator like P C or ^
  40. 11: ,
  41. 12: function with , seperated three parameters
  42. 13: variable of Sigma function
  43. */
  44. var type0={0:true,1:true,3:true,4:true,6:true,8:true,9:true,12:true,13:true},//type2:true,type4:true,type9:true,type11:true,type21:true,type22
  45. type1={0:true,1:true,2:true,3:true,4:true,5:true,6:true,7:true,8:true,9:true,10:true,11:true,12:true,13:true},//type3:true,type5:true,type7:true,type23
  46. type_1={0:true,3:true,4:true,8:true,12:true,13:true},
  47. empty={},
  48. type_3={0:true,1:true,3:true,4:true,6:true,8:true,12:true,13:true},//type_5:true,type_7:true,type_23
  49. type6={1:true},
  50. newAr=[[],
  51. ["1","2","3","7","8","9","4","5","6","+","-","*","/","(",")","^","!","P","C","e","0",".",",","n"],
  52. ["pi","ln","Pi"],
  53. ["sin","cos","tan","Del","int","Mod","log","pow"],
  54. ["asin","acos","atan","cosh","root","tanh","sinh"],
  55. ["acosh","atanh","asinh","Sigma"]];
  56. function match(str1,str2,i,x){
  57. for(var f=0;f<x;f++){
  58. if (str1[i+f]!==str2[f])
  59. return false;
  60. }
  61. return true;
  62. }
  63. Mexp.addToken=function(tokens){
  64. for(i=0;i<tokens.length;i++){
  65. x=tokens[i].token.length;
  66. var temp=-1;
  67. //newAr is a specially designed data structure in which 1D array at location one of 2d array has all string with length 1 2 with 2 and so on
  68. if (x<newAr.length) //match to check if token is really huge and not existing
  69. //if not checked it will break in next line as undefined index
  70. for(y=0;y<newAr[x].length;y++){
  71. if (tokens[i].token===newAr[x][y]){
  72. temp=token.indexOf(newAr[x][y]);
  73. break;
  74. }
  75. }
  76. if (temp===-1) {
  77. token.push(tokens[i].token);
  78. type.push(tokens[i].type);
  79. if(newAr.length<=tokens[i].token.length)
  80. newAr[tokens[i].token.length]=[];
  81. newAr[tokens[i].token.length].push(tokens[i].token);
  82. eva.push(tokens[i].value);
  83. show.push(tokens[i].show);
  84. }
  85. else {
  86. token[temp]=tokens[i].token;
  87. type[temp]=tokens[i].type;
  88. eva[temp]=tokens[i].value;
  89. show[temp]=tokens[i].show;
  90. }
  91. }
  92. };
  93. Mexp.lex=function(inp,tokens){
  94. 'use strict';
  95. var str=[{type:4,value:"(",show:"(",pre:0}];
  96. var ptc=[]; //Parenthesis to close at the beginning is after one token
  97. var inpStr=inp;
  98. var key;
  99. var pcounter=0;
  100. var allowed=type0;
  101. var bracToClose=0;
  102. var asterick=empty;
  103. var prevKey='';
  104. var i,x,y;
  105. if(typeof tokens!=="undefined")
  106. Mexp.addToken(tokens);
  107. var obj={};
  108. for(i=0;i<inpStr.length;i++){
  109. if (inpStr[i]==' ') {
  110. continue;
  111. }
  112. key='';
  113. sec:for(x=(inpStr.length-i>(newAr.length-2)?newAr.length-1:inpStr.length-i);x>0;x--){
  114. for(y=0;y<newAr[x].length;y++){
  115. if (match(inpStr,newAr[x][y],i,x)){
  116. key=newAr[x][y];
  117. break sec;
  118. }
  119. }
  120. }
  121. i+=key.length-1;
  122. if(key===''){
  123. throw(new Mexp.exception("Can't understand after "+inpStr.slice(i)));
  124. }
  125. var index=token.indexOf(key);
  126. var cToken=key;
  127. var cType=type[index];
  128. var cEv=eva[index];
  129. var cPre=preced[cType];
  130. var cShow=show[index];
  131. var pre=str[str.length-1];
  132. for(j=ptc.length;j--;){ //loop over ptc
  133. if(ptc[j]===0){
  134. if([0,2,3,5,9,11,12,13].indexOf(cType)!==-1){
  135. if(allowed[cType]!==true){
  136. throw(new Mexp.exception(key+" is not allowed after "+prevKey));
  137. }
  138. str.push({value:")",type:5,pre:0,show:")"});
  139. allowed=type1;
  140. asterick=type_3;
  141. inc(ptc,-1).pop();
  142. }
  143. }
  144. }
  145. if(allowed[cType]!==true){
  146. throw(new Mexp.exception(key+" is not allowed after "+prevKey));
  147. }
  148. if(asterick[cType]===true){
  149. cType=2;
  150. cEv=Mexp.math.mul;
  151. cShow="&times;";
  152. cPre=3;
  153. i=i-key.length;
  154. }
  155. obj={value:cEv,type:cType,pre:cPre,show:cShow};
  156. if(cType===0){
  157. allowed=type0;
  158. asterick=empty;
  159. inc(ptc,2).push(2);
  160. str.push(obj);
  161. str.push({value:"(",type:4,pre:0,show:"("});
  162. }
  163. else if(cType===1){
  164. if(pre.type===1){
  165. pre.value+=cEv;
  166. inc(ptc,1);
  167. }
  168. else {
  169. str.push(obj);
  170. }
  171. allowed=type1;
  172. asterick=type_1;
  173. }
  174. else if(cType===2){
  175. allowed=type0;
  176. asterick=empty;
  177. inc(ptc,2);
  178. str.push(obj);
  179. }
  180. else if(cType===3){//constant
  181. str.push(obj);
  182. allowed=type1;
  183. asterick=type_3;
  184. }
  185. else if(cType===4){
  186. pcounter+=ptc.length;
  187. ptc=[];
  188. bracToClose++;
  189. allowed=type0;
  190. asterick=empty;
  191. str.push(obj);
  192. }
  193. else if(cType===5){
  194. if(!bracToClose){
  195. throw(new Mexp.exception("Closing parenthesis are more than opening one, wait What!!!"));
  196. }
  197. while(pcounter--){ //loop over ptc
  198. str.push({value:")",type:5,pre:0,show:")"});
  199. }
  200. pcounter=0;
  201. bracToClose--;
  202. allowed=type1;
  203. asterick=type_3;
  204. str.push(obj);
  205. }
  206. else if(cType===6){
  207. if(pre.hasDec){
  208. throw(new Mexp.exception("Two decimals are not allowed in one number"));
  209. }
  210. if(pre.type!==1){
  211. pre={value:0,type:1,pre:0}; //pre needs to be changed as it will the last value now to be safe in later code
  212. str.push(pre);
  213. inc(ptc,-1);
  214. }
  215. allowed=type6;
  216. inc(ptc,1);
  217. asterick=empty;
  218. pre.value+=cEv;
  219. pre.hasDec=true;
  220. }
  221. else if(cType===7){
  222. allowed=type1;
  223. asterick=type_3;
  224. inc(ptc,1);
  225. str.push(obj);
  226. }
  227. if(cType===8){
  228. allowed=type0;
  229. asterick=empty;
  230. inc(ptc,4).push(4);
  231. str.push(obj);
  232. str.push({value:"(",type:4,pre:0,show:"("});
  233. }
  234. else if(cType===9){
  235. if(pre.type===9){
  236. if(pre.value===Mexp.math.add){
  237. pre.value=cEv;
  238. pre.show=cShow;
  239. inc(ptc,1);
  240. }
  241. else if(pre.value===Mexp.math.sub&&cShow==='-'){
  242. pre.value=Mexp.math.add;
  243. pre.show='+';
  244. inc(ptc,1);
  245. }
  246. }
  247. else if(pre.type!==5&&pre.type!==7&&pre.type!==1&&pre.type!==3&&pre.type!==13){//changesign only when negative is found
  248. if(cToken==='-'){//do nothing for + token
  249. //don't add with the above if statement as that will run the else statement of parent if on Ctoken +
  250. allowed=type0;
  251. asterick=empty;
  252. inc(ptc,2).push(2);
  253. str.push({value:Mexp.math.changeSign,type:0,pre:21,show:"-"});
  254. str.push({value:"(",type:4,pre:0,show:"("});
  255. }
  256. }
  257. else{
  258. str.push(obj);
  259. inc(ptc,2);
  260. }
  261. allowed=type0;
  262. asterick=empty;
  263. }
  264. else if(cType===10){
  265. allowed=type0;
  266. asterick=empty;
  267. inc(ptc,2);
  268. str.push(obj);
  269. }
  270. else if(cType===11){
  271. allowed=type0;
  272. asterick=empty;
  273. str.push(obj);
  274. }
  275. else if(cType===12){
  276. allowed=type0;
  277. asterick=empty;
  278. inc(ptc,6).push(6);
  279. str.push(obj);
  280. str.push({value:"(",type:4,pre:0});
  281. }
  282. else if(cType===13){
  283. allowed=type1;
  284. asterick=type_3;
  285. str.push(obj);
  286. }
  287. inc(ptc,-1);
  288. prevKey=key;
  289. }
  290. for(var j=ptc.length;j--;){ //loop over ptc
  291. if(ptc[j]===0){
  292. str.push({value:")",show:")",type:5,pre:3});
  293. inc(ptc,-1).pop();
  294. }
  295. }
  296. if (allowed[5]!==true) {
  297. throw(new Mexp.exception("complete the expression"));
  298. }
  299. while(bracToClose--)
  300. str.push({value:")",show:")",type:5,pre:3});
  301. str.push({type:5,value:")",show:")",pre:0});
  302. // console.log(str);
  303. return new Mexp(str);
  304. };
  305. module.exports=Mexp;