Advertisement
Guest User

Untitled

a guest
Oct 27th, 2016
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.34 KB | None | 0 0
  1. Object.defineProperty(Array.prototype, "top", {
  2. get: function(){ return this[this.length - 1]; },
  3. set: function(v){ return this[this.length - 1] = v; }
  4. });
  5.  
  6. class Operator {
  7. constructor(symbol, monad, dyad, precedence, assoc){
  8. this.symbol = symbol;
  9. this.monad = monad;
  10. this.dyad = dyad;
  11. this.precedence = precedence;
  12. this.assoc = !!assoc;
  13. }
  14.  
  15. get left(){
  16. return !this.assoc;
  17. }
  18.  
  19. get right(){
  20. return this.assoc;
  21. }
  22.  
  23. copy(){
  24. return new Operator(this.symbol, this.monad, this.dyad, this.precedence, this.assoc);
  25. }
  26.  
  27. toString(){
  28. return `${this.symbol}`
  29. }
  30. }
  31.  
  32. class Value {
  33. constructor(value, type){
  34. this.value = value;
  35. this.type = type;
  36. }
  37.  
  38. toString(){
  39. return `${this.value}`;
  40. }
  41. }
  42.  
  43. class Func {
  44. constructor(name, effect){
  45. this.name = name;
  46. this.effect = effect;
  47. }
  48.  
  49. copy(){
  50. return new Func(this.name, this.effect);
  51. }
  52. }
  53.  
  54. class OperatorNode {
  55. constructor(operator, children){
  56. this.operator = operator;
  57. this.children = children;
  58. }
  59.  
  60. toString(){
  61.  
  62. }
  63. }
  64.  
  65. const disp = (token) => token.value || token.symbol || token;
  66.  
  67. class ConcreteSyntaxTree {
  68. constructor(props){
  69. Object.assign(this, props);
  70. }
  71.  
  72. parse(str){
  73. let tokens = [];
  74. let ops = [...this.operators.keys()];
  75. for(let i = 0; i < str.length; i++){
  76. let cur = str[i];
  77. // console.log(cur, i);
  78. if(ops.some(e => e[0] === cur)){
  79. let build = cur;
  80. while(ops.some(e => e.indexOf(build + str[i + 1]) === 0)){
  81. build += str[++i];
  82. }
  83. tokens.push(this.operators.get(build).copy());
  84. } else if(cur === "," || cur === "(" || cur === ")"){
  85. tokens.push(cur);
  86. } else if(/[0-9]/.test(cur)){
  87. let build = "";
  88. while(/[0-9]/.test(str[i])){
  89. build += str[i++];
  90. }
  91. tokens.push(new Value(build, "number"));
  92. i--;
  93. } else if(/\w/.test(cur)){
  94. let build = "";
  95. while(/\w/.test(str[i]) && str[i]){
  96. build += str[i++];
  97. }
  98. if(this.funcs.has(build)){
  99. tokens.push(this.funcs.get(build).copy());
  100. } else {
  101. tokens.push(new Value(build, "variable"));
  102. }
  103. i--;
  104. }
  105. }
  106. return tokens;
  107. }
  108.  
  109. // TODO: error handling
  110. shunt(str){
  111. let tokens = this.parse(str);
  112. console.log(tokens.map(disp));
  113. let queue = [];
  114. let stack = [];
  115. let fArity = [];
  116. let previous = null;
  117. while(tokens.length){
  118. let token = tokens.shift();
  119. if(token instanceof Value){
  120. queue.push(token);
  121. } else if(token instanceof Func){
  122. fArity.push(1);
  123. stack.push(token);
  124. } else if(token instanceof Operator){
  125. if(!previous || previous instanceof Operator){
  126. token.arity = 1;
  127. } else {
  128. token.arity = 2;
  129. }
  130. while(stack.top instanceof Operator &&
  131. token.arity === 2 && (
  132. token.left && token.precedence <= stack.top.precedence ||
  133. token.right && token.precedence < stack.top.precedence
  134. )){
  135. queue.push(stack.pop());
  136. }
  137. stack.push(token);
  138. } else if(token === ","){
  139. fArity.top++;
  140. while(stack.top !== "(")
  141. queue.push(stack.pop());
  142. } else if(token === "("){
  143. stack.push(token);
  144. } else if(token === ")"){
  145. while(stack.top !== "(")
  146. queue.push(stack.pop());
  147.  
  148. stack.pop();
  149. if(stack.top instanceof Func){
  150. let func = stack.pop();
  151. func.arity = fArity.pop();
  152. queue.push(func);
  153. }
  154. }
  155. previous = token;
  156. console.log(disp(token), queue.map(disp), stack.map(disp));
  157. }
  158.  
  159. return queue.concat(stack.reverse());
  160. }
  161.  
  162. // convert to an CST
  163. convert(str){
  164. let tokens = this.shunt(str);
  165. let stack = [];
  166. for(let token of tokens){
  167. if(typeof token.arity !== "undefined"){
  168. let args = stack.splice(-token.arity);
  169. stack.push(new OperatorNode(token, args));
  170. } else {
  171. stack.push(token);
  172. }
  173. }
  174. return stack.shift();
  175. }
  176.  
  177. compile(str){
  178. let tree = this.convert(str);
  179. let vrn = 0;
  180. let compiled = "";
  181. let traverse = (node) => {
  182. if(!(node instanceof OperatorNode)) return node.value;
  183. // console.log("CHILDREN", node.children[1]);
  184. let vr = this.allocator(vrn++);
  185. console.log(vr, node);
  186. if(node.operator instanceof Operator){
  187. if(node.operator.arity === 2){ // dyad
  188. let leftSide = traverse(node.children[0]);
  189. let rightSide = traverse(node.children[1]);
  190. compiled += `${vr} = ${leftSide};\n`;
  191. compiled += `${vr} = ${node.operator.dyad(vr, rightSide)};\n`;
  192. } else {
  193. let side = traverse(node.children[0]);
  194. compiled += `${vr} = ${node.operator.monad(side)};\n`;
  195. }
  196. return vr;
  197. } else if(node.operator instanceof Func){
  198. // TODO
  199. }
  200. }
  201. traverse(tree);
  202. return compiled;
  203. }
  204. }
  205.  
  206. ConcreteSyntaxTree.NO_CASE = Symbol("no case is defined");
  207.  
  208. // compiles to javascript
  209. let test = new ConcreteSyntaxTree({
  210. allocator: (index) => `_${index.toString(36)}`,
  211. operators: new Map([
  212. ["+", new Operator(
  213. "+",
  214. (x) => `Math.abs(${x})`,
  215. (x, y) => `${x}+${y}`,
  216. 2000
  217. )],
  218. ["-", new Operator(
  219. "-",
  220. (x) => `-${x}`,
  221. (x, y) => `${x}-${y}`,
  222. 2000
  223. )],
  224. ["*", new Operator(
  225. "*",
  226. (x) => `x*x`,
  227. (x, y) => `${x}*${y}`,
  228. 4000
  229. )],
  230. ["/", new Operator(
  231. "/",
  232. (x) => `1/x`,
  233. (x, y) => `${x}/${y}`,
  234. 4000
  235. )],
  236. ["//", new Operator(
  237. "//",
  238. ConcreteSyntaxTree.NO_CASE,
  239. (x, y) => `Math.floor(${x}/${y})`,
  240. 4000
  241. )],
  242. ["^", new Operator(
  243. "^",
  244. ConcreteSyntaxTree.NO_CASE,
  245. (x, y) => `Math.pow(${x},${y})`,
  246. 6000,
  247. true
  248. )]
  249. ]),
  250. funcs: new Map([
  251. ["print", new Func("print", (a, b) => `console.log(${a},${b}),${b}`)]
  252. ])
  253. });
  254.  
  255. // TODO: figure out why this doesn't work
  256. let str = "1 * -2 / 3 + 4";
  257.  
  258. // console.log(test.parse(str));
  259. console.log(str);
  260. console.log(test.shunt(str).map(e=>e+""));
  261. // console.log();
  262. // console.log(test.convert(str));
  263. // console.log();
  264. // console.log(test.compile(str));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement