Fantasy 8Bit system (F8), is a fantasy 8bit console and a set of libraries for creating fantasy 8bit consoles.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

159 lines
2.6KB

  1. const OP = require('./op.js');
  2. function TokenStream(input){
  3. var pos = 0;
  4. function peek(){
  5. return (pos < input.length) ? input[pos] : null;
  6. }
  7. function next(){
  8. if (pos < input.length){
  9. let v = input[pos];
  10. pos += 1;
  11. return v;
  12. }
  13. return null;
  14. }
  15. function line(){
  16. return (pos < input.length) ? input[pos].line : -1;
  17. }
  18. function col(){
  19. return (pos < input.length) ? input[pos].col : -1;
  20. }
  21. function eol(){
  22. return (pos < input.length - 1) ? (input[pos].line !== input[pos+1].line) : true;
  23. }
  24. function eof(){
  25. return (pos >= input.length);
  26. }
  27. function die(msg){
  28. throw new Error(msg + " Line: " + input[pos].line + ", Col: " + input[pos].col);
  29. }
  30. return {
  31. peek: peek,
  32. next: next,
  33. line: line,
  34. col: col,
  35. eof, eof,
  36. die: die
  37. };
  38. }
  39. var stream = null;
  40. function isTokenType(type, val){
  41. let t = stream.peek();
  42. if (t !== null && t.type === type){
  43. if (!val || t.val === val)
  44. return true;
  45. }
  46. return false;
  47. }
  48. function isPunc(ch){
  49. return isTokenType("punc", ch);
  50. }
  51. function isOpCode(ch){
  52. return isTokenType("opcode", ch);
  53. }
  54. function isLabel(ch){
  55. return isTokenType("label", ch);
  56. }
  57. function isDirective(ch){
  58. return isTokenType("directive", ch);
  59. }
  60. function isOp(ch){
  61. return isTokenType("op", ch);
  62. }
  63. function skipPunc(ch){
  64. if (isPunc(ch)){
  65. stream.next();
  66. } else {
  67. stream.die("Unexpected punctuation '" + ch + "'.");
  68. }
  69. }
  70. parseDelimited(s,e,d,parser){
  71. let toEOL = (s === null || e === null);
  72. let a = [];
  73. let first = true;
  74. if (!toEOL){skipPunc(s);}
  75. while (!stream.eof() && ((!toEOL && isPunc(e)) || (toEOL && !stream.eol()))){
  76. if (first){
  77. first = false;
  78. } else {skipPunk(d);}
  79. a.push(parser());
  80. }
  81. if (!toEOL){skipPunc(e);}
  82. return a;
  83. }
  84. parseOpCode(){
  85. let val = stream.next();
  86. let mode = 0; // Guess between absolute and zero page.
  87. let args = []; // TODO: Finish figuring out how to get the argument list!
  88. if (isOp("#")){
  89. stream.next();
  90. mode = 1; // Immediate
  91. } else if (isPunc("(")){
  92. mode = 2; // Indirect
  93. // TODO: Use parseDelimited()
  94. }
  95. return {
  96. type: "opcode",
  97. val: val,
  98. args: args,
  99. mode: mode
  100. };
  101. }
  102. parseAtom(){
  103. if (isPunc("(")){
  104. stream.next();
  105. let exp = parseExpression();
  106. if (isPunc(")")){
  107. stream.next();
  108. return exp;
  109. }
  110. } else if (isOpCode()){
  111. return parseOpCode();
  112. }
  113. }
  114. parse(tokens){
  115. let p = {
  116. type: "prog",
  117. expressions: [];
  118. };
  119. stream = TokenStream(tokens);
  120. while (!stream.eof()){
  121. p.expressions.push(parseExpression());
  122. }
  123. stream = null;
  124. return p;
  125. }
  126. module.exports = Object.freeze({
  127. parse: parse
  128. });