my blog lives here now
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
3.1 KiB

2 years ago
  1. let draw = SVG().addTo('#forth').size('100%', '100%')
  2. let stack_element = (container, text) => {
  3. let group = container.group()
  4. group.add(
  5. container.rect()
  6. .size(100, 25)
  7. .stroke('#000').fill('#ddd')
  8. .attr('stroke-width', 2));
  9. group.add(container.text(text).dmove((65 - text.length) / 2, -2));
  10. console.log(group);
  11. return group;
  12. }
  13. let the_code = [
  14. [ 'push', 2 ],
  15. [ 'push', 3 ],
  16. [ 'push', 4 ],
  17. [ 'mul' ],
  18. [ 'add' ]
  19. ]
  20. let the_stack = [], pc = 0, final = false;
  21. let stack_container = draw.nested().move(draw.width() - '10%', 0)
  22. let code_node = document.getElementById('code');
  23. let push_val = (int) => {
  24. let the_element =
  25. stack_element(stack_container, int.toString()).move(10, 0);
  26. the_element.animate(100, 0, 'now').move(10, 10);
  27. the_stack.forEach(elem => elem.svg.animate(100, 0, 'now').dy(25));
  28. the_stack.push({ svg: the_element, val: int });
  29. }
  30. let pop_val = () => {
  31. let item = the_stack.pop()
  32. item.svg.remove();
  33. the_stack.forEach(elem => elem.svg.dy(-25));
  34. return item.val;
  35. }
  36. let render_code = (code, pc) => {
  37. while (code_node.firstChild) {
  38. code_node.removeChild(code_node.firstChild);
  39. }
  40. let list = document.createElement('ul');
  41. list.style = 'list-style-type: none;';
  42. code.forEach((instruction, idx) => {
  43. let i_type = instruction[0];
  44. let li = document.createElement('li');
  45. if (idx == pc) {
  46. let cursor = document.createElement('span')
  47. cursor.innerText = '> ';
  48. cursor.classList.add('instruction-cursor');
  49. li.appendChild(cursor);
  50. }
  51. let type_field = document.createElement('span');
  52. type_field.innerText = i_type;
  53. type_field.classList.add('instruction');
  54. li.appendChild(type_field);
  55. for (let i = 1; i < instruction.length; i++) {
  56. li.append(' ');
  57. let operand_field = document.createElement('span');
  58. operand_field.innerText = instruction[i];
  59. operand_field.classList.add('operand');
  60. li.appendChild(operand_field);
  61. }
  62. list.appendChild(li);
  63. });
  64. code_node.appendChild(list);
  65. };
  66. let reset = () => {
  67. the_stack.forEach(e => e.svg.remove());
  68. the_stack = [];
  69. pc = 0;
  70. final = false;
  71. document.getElementById('step').disabled = false;
  72. render_code(the_code, 0);
  73. }
  74. let step = () => {
  75. if (!final) {
  76. const insn = the_code[pc++];
  77. switch (insn[0]) {
  78. case 'push':
  79. push_val(insn[1]);
  80. break;
  81. case 'add':
  82. if (the_stack.length < 2) {
  83. console.error("machine error");
  84. document.getElementById('step').disabled = true;
  85. } else {
  86. let x = pop_val(), y = pop_val();
  87. push_val(x + y);
  88. }
  89. break;
  90. case 'mul':
  91. if (the_stack.length < 2) {
  92. console.error("machine error");
  93. document.getElementById('step').disabled = true;
  94. } else {
  95. let x = pop_val(), y = pop_val();
  96. push_val(x * y);
  97. }
  98. break;
  99. }
  100. }
  101. render_code(the_code, pc);
  102. if (pc >= the_code.length) {
  103. console.log("final state");
  104. document.getElementById('step').disabled = true;
  105. final = true;
  106. }
  107. }
  108. render_code(the_code, pc);