[关闭]
@dsy12138 2018-03-01T04:16:21.000000Z 字数 4381 阅读 372

算法
分形

一些算法问题的汇总(3)

  Ever tried. Ever failed.

  No matter. Try again.

  Fail again. Fail better.

       --Peter Dinklage

brainFuck语法编译器

brainFuck语言是一门非常简单的基于栈的语言,只有以下几种操作符
"+": 指针指向单元数值自增1
"-": 指针指向单元数值自减1
">": 指针向右移动一格
"<": 指针向左移动一格
".": 输出指针指向的数值(ASCII码形式)
",": 接受输入的数值

前言

  虽然本算法称为编译器,但其实仅仅只是将原本的brainFuck语言转换成了javascript语言,并做了一些缩进,其目的只是为了好玩。利用这个brainFuck编译器,你可以写自己的brainFuck语言,比如一个“Hello World!”就可以是“++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>++.>+.+++++++..+++.<<++.>+++++++++++++++.>.+++.------.--------.<<+.<.”这么长的奇怪代码。当然,要自己写一个这样像密码一般的字符串也不是一件容易的事,或许真的是件brainFuck!的事。权当娱乐,重在开心。

代码如下:

  1. function Compile(syntax, params) {
  2. 'use strict';
  3. const MAXSIZE = 40;
  4. let cache = [], count = 0, code = undefined, i, memory = MAXSIZE;
  5. if (params && params.hasOwnProperty("memory") && params.memory > 0) {
  6. memory = params.memory;
  7. } else if (params) {
  8. for (i=0; i<params.length; i++)
  9. params[i] = paraseInt(params[i]) | 0;
  10. }
  11. let canDo = (x) => x == ">" || x == "<" || x == "+" || x == "-";
  12. let addp = (x) => "pointer+=" + x + ";";
  13. let subp = (x) => "pointer-=" + x + ";";
  14. let adder = (x) => "stack[pointer]+=" + x + ";";
  15. let suber = (x) => "stack[pointer]-=" + x + ";";
  16. let output = "output.push(stack[pointer]);";
  17. let input = (x) => "stack[pointer]=JSON.parse(" + JSON.stringify(x) + ");";
  18. let whs = "while(stack[pointer]){";
  19. let whe = "}";
  20. let debug = (x) => "console.log('stack memory:' + stack.join('|') + ' current pointer:' + pointer + ' at:' + " + x + ");";
  21. let record = { operating: NaN, count: NaN };
  22. syntax += "#";
  23. cache.push("let stack=[];");
  24. cache.push("stack.length=" + memory + ";");
  25. cache.push("stack.fill(0);");
  26. cache.push("let pointer=0;");
  27. cache.push("let output=[];");
  28. for (i = 0; i < syntax.length; i++) {
  29. if (record.operating == syntax[i]) {
  30. record.count++;
  31. continue;
  32. } else if (!!record.operating) {
  33. switch (record.operating) {
  34. case ">": cache.push(addp(record.count)); break;
  35. case "<": cache.push(subp(record.count)); break;
  36. case "+": cache.push(adder(record.count)); break;
  37. case "-": cache.push(suber(record.count)); break;
  38. }
  39. }
  40. if (canDo(syntax[i])) {
  41. record.operating = syntax[i];
  42. record.count = 1;
  43. } else {
  44. record.operating = record.count = NaN;
  45. }
  46. switch (syntax[i]) {
  47. case ",": cache.push(input(params[count++])); break;
  48. case "[": cache.push(whs); break;
  49. case "]": cache.push(whe); break;
  50. case ".": cache.push(output); break;
  51. }
  52. if (params &&
  53. params.hasOwnProperty("debug") &&
  54. params.debug &&
  55. (syntax[i] == "+" || syntax[i] == "-")) {
  56. cache.push(debug(i + 1));
  57. }
  58. }
  59. cache.push("for(let i=0;i<output.length;i++){output[i]=String.fromCharCode(output[i]);}");
  60. cache.push("console.log(output.join(''));");
  61. return {
  62. brainFuck: new Function(cache.join("")),
  63. codeLength: cache.length
  64. };
  65. }
  66. // Hello World!
  67. var helloworld = Compile("++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>++.>+.+++++++..+++.<<++.>+++++++++++++++.>.+++.------.--------.<<+.<.");
  68. helloworld.brainFuck();

计算公式转逆波兰式(计算器原理)

  逆波兰式也叫也叫后缀表达式,之所以要转换为后缀表达式,原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中序表达式是非常复杂的结构。相对的,逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。
  所以,在计算机中运算这样的一个公式(123+abc)*d-(a+b)/e,我们一般先转化为逆波兰式,再在栈中求解计算。

代码如下:

  1. var classes = new Map();
  2. classes.set('+', [5, 6]);
  3. classes.set('-', [7, 8]);
  4. classes.set('*', [1, 2]);
  5. classes.set('/', [3, 4]);
  6. classes.set('(', [11, 0]);
  7. classes.set(')', [13, 12]);
  8. classes.set('#', [14, 14]);
  9. function check(sign) {
  10. if (sign == "#" || sign == "(" || sign == ")") {
  11. return false;
  12. }
  13. return true;
  14. }
  15. /**
  16. * 编译成逆波兰式
  17. *
  18. * @param {*} str 计算公式
  19. */
  20. function compile(str) {
  21. let stack = [], output = "", pointer = 0, sign, pushIcon;
  22. str = "#"+str+"#";
  23. for (let i=0; i<str.length; i++) {
  24. if (!!classes.get(str[i])) {
  25. pushIcon = true;
  26. for(let j=stack.length-1; j>=0; j--) {
  27. let inLevel = classes.get(stack[stack.length - 1])[0];
  28. let outLevel = classes.get(str[i])[1];
  29. if (stack[stack.length - 1] == "(" && str[i] == ")") {
  30. stack.pop();
  31. pushIcon = false;
  32. break;
  33. }
  34. if (inLevel < outLevel)
  35. output += " " + stack.pop();
  36. else
  37. break;
  38. }
  39. if (stack[stack.length - 1] == "#" && str[i] == "#")
  40. return output.split(" ").filter((x) => x!=="").join(" ");
  41. if (pushIcon) {
  42. stack.push(str[i]);
  43. output += " ";
  44. }
  45. } else {
  46. output+=str[i];
  47. }
  48. }
  49. console.err("equation is error!");
  50. }
  51. /**
  52. * 运算逆波兰式
  53. *
  54. * @param {*} equation 逆波兰式
  55. * @param {*} params 参数
  56. */
  57. function run(equation, params) {
  58. let machine = equation.split(" ");
  59. let stack = [];
  60. for (let element of machine) {
  61. if (classes.get(element)) {
  62. let after = stack.pop();
  63. let before = stack.pop();
  64. switch(element) {
  65. case "+": stack.push(before + after);break;
  66. case "-": stack.push(before - after);break;
  67. case "*": stack.push(before * after);break;
  68. case "/": stack.push(before / after);break;
  69. default:
  70. return new Error("can't calculate it!!!");
  71. }
  72. } else if (isNaN(element)) {
  73. if (params && params.hasOwnProperty(element))
  74. stack.push(params[element]);
  75. else
  76. return new Error("no this params!!!");
  77. } else
  78. stack.push(parseFloat(element));
  79. }
  80. return stack.pop();
  81. }
  82. var result = compile("(123+abc)*d-(a+b)/e");
  83. console.log(result);
  84. var value = run(result, {abc: 1, d: 1, a: 1, b: 1, e: 1});
  85. console.log(value);
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注