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.

224 lines
4.2KB

  1. function GetTextStream(input){
  2. var pos = 0;
  3. var line = 0;
  4. var col = 0;
  5. function peek(){
  6. return input.charAt(pos);
  7. }
  8. function next(){
  9. let c = input.charAt(pos);
  10. pos += 1;
  11. if (c === "\n"){
  12. line += 1;
  13. col = 0;
  14. } else {col += 1;}
  15. return c;
  16. }
  17. function eof(){
  18. return (input.charAt(pos) === "");
  19. }
  20. function getLine(){return line;}
  21. function getCol(){return col;}
  22. function die(msg){
  23. throw new Error(msg + " Line: " + line + ", Col: " + col);
  24. }
  25. return {
  26. peek: peek,
  27. next: next,
  28. eof: eof,
  29. line: getLine,
  30. col: getCol,
  31. die: die
  32. };
  33. }
  34. // ----------------------------------------------
  35. // VALIDATORS
  36. // ----------------------------------------------
  37. function isWhiteSpace(c){
  38. return ("\t\n ".indexOf(c) >= 0);
  39. }
  40. function isStringStart(c){
  41. return (c === "\"" || c === "'");
  42. }
  43. function isNumType(c){
  44. return ("$%".indexOf(c) >= 0 || isDigit(c));
  45. }
  46. function isDigit(c){
  47. return /[0-9]/i.test(c);
  48. }
  49. function isHex(c){
  50. return /[0-9a-fA-F]/i.test(c);
  51. }
  52. function isBinary(c){
  53. return ("01".indexOf(c) >= 0);
  54. }
  55. function isLabelStart(c){
  56. return /[a-zA-Z_]/i.test(c);
  57. }
  58. function isLabel(c){
  59. return (isLabelStart(c) || isDigit(c));
  60. }
  61. function isPunctuation(c){
  62. return (",()".indexOf(c) >= 0);
  63. }
  64. function isOp(c){
  65. return ("=+-/*#".indexOf(c) >= 0);
  66. }
  67. // -----------------------------------------------------------
  68. // TOKENIZER CLASS
  69. // -----------------------------------------------------------
  70. class Tokenizer{
  71. constructor(input){
  72. this.__stream = GetTextStream(input);
  73. }
  74. genTokenObject(type, val){
  75. return {
  76. type: type,
  77. val: val,
  78. line: this.__stream.line(),
  79. col: this.__stream.col()
  80. }
  81. }
  82. // ----------------------------------------------
  83. // Read Operations
  84. // ----------------------------------------------
  85. skipComment(){
  86. this.readWhile((c)=>{return c != "\n";});
  87. this.__stream.next();
  88. }
  89. readHex(){
  90. this.__stream.next();
  91. var str = this.readWhile(isHex);
  92. return this.genTokenObject('number', parseInt(str, 16));
  93. }
  94. readBinary(){
  95. this.__stream.next();
  96. var str = this.readWhile(isBinary);
  97. return this.genTokenObject('number', parseInt(str, 2));
  98. }
  99. readNumber(){
  100. let c = this.__stream.peek();
  101. if (c === "$")
  102. return this.readHex();
  103. if (c === "%")
  104. return this.readBinary();
  105. var str = this.readWhile(isDigit);
  106. return this.genTokenObject('number', parseInt(str));
  107. }
  108. readString(end){
  109. var str = "";
  110. var escaped = false;
  111. this.__stream.next();
  112. while (!this.__stream.eof()){
  113. let c = this.__stream.next();
  114. if (escaped){
  115. str += c;
  116. escaped = false;
  117. } else if (c === "\\"){
  118. escaped = true;
  119. } else if (c === end){
  120. break;
  121. } else {
  122. str += c;
  123. }
  124. }
  125. return this.genTokenObject('string', str);
  126. }
  127. readDirective(){
  128. var str = this.__stream.next() + this.readWhile(isLabel);
  129. return this.genTokenObject('directive', str);
  130. }
  131. readLabel(){
  132. var str = this.readWhile(isLabel);
  133. return this.genTokenObject('label', str);
  134. }
  135. readWhile(validator){
  136. var str = "";
  137. while (!this.__stream.eof() && validator(this.__stream.peek()))
  138. str += this.__stream.next();
  139. return str;
  140. }
  141. nextToken(){
  142. this.readWhile(isWhiteSpace);
  143. if (this.__stream.eof()){return null;}
  144. let c = this.__stream.peek();
  145. if (c === ";"){
  146. this.skipComment();
  147. return this.nextToken();
  148. } else if (isStringStart(c)){
  149. return this.readString(c);
  150. } else if (isNumType(c)){
  151. return this.readNumber();
  152. } else if (isLabelStart(c)){
  153. return this.readLabel();
  154. } else if (c === "."){
  155. return this.readDirective();
  156. } else if (isPunctuation(c)){
  157. return this.genTokenObject('punc', this.__stream.next());
  158. } else if (isOp(c)){
  159. return this.genTokenObject('op', this.__stream.next());
  160. }
  161. this.__stream.die("Unable to process character '" + c + "'.");
  162. }
  163. }
  164. function tokenize(input){
  165. var tokenizer = new Tokenizer(input);
  166. var tokens = [];
  167. var t = tokenizer.nextToken();
  168. while (t !== null){
  169. tokens.push(t);
  170. t = tokenizer.nextToken();
  171. }
  172. return tokens;
  173. }
  174. module.exports = Object.freeze({
  175. Tokenizer:Tokenizer,
  176. tokenize:tokenize
  177. });