Tokenizer.java 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package me.hammerle.snuviscript.token;
  2. import java.io.InputStream;
  3. import java.util.ArrayList;
  4. import me.hammerle.snuviscript.exceptions.PreScriptException;
  5. import static me.hammerle.snuviscript.token.TokenType.*;
  6. public class Tokenizer
  7. {
  8. private StreamCharReader stream = null;
  9. private final ArrayList<Token> tokens = new ArrayList<>();
  10. private int line = 1;
  11. private int next()
  12. {
  13. return stream.readChar();
  14. }
  15. private int peek()
  16. {
  17. return stream.peekChar();
  18. }
  19. private boolean next(char c)
  20. {
  21. if(peek() == c)
  22. {
  23. next();
  24. return true;
  25. }
  26. return false;
  27. }
  28. private void add(TokenType type)
  29. {
  30. tokens.add(new Token(type, line));
  31. }
  32. private void add(TokenType type, Object data)
  33. {
  34. tokens.add(new DataToken(type, line, data));
  35. }
  36. private void add(char c, TokenType t1, TokenType t2, TokenType t3, TokenType t4)
  37. {
  38. int peek = peek();
  39. if(peek == c)
  40. {
  41. next();
  42. if(peek() == '=')
  43. {
  44. next();
  45. add(t1);
  46. }
  47. else
  48. {
  49. add(t2);
  50. }
  51. }
  52. else if(peek == '=')
  53. {
  54. next();
  55. add(t3);
  56. }
  57. else
  58. {
  59. add(t4);
  60. }
  61. }
  62. public Token[] tokenize(InputStream in)
  63. {
  64. stream = new StreamCharReader(in);
  65. tokens.clear();
  66. line = 1;
  67. int c;
  68. while((c = Tokenizer.this.next()) != -1)
  69. {
  70. handleChar(c);
  71. }
  72. add(EOF);
  73. return tokens.toArray(new Token[tokens.size()]);
  74. }
  75. private void handleChar(int c)
  76. {
  77. if(Character.isLetter(c) || c == '_')
  78. {
  79. handleLiteral(c, TokenType.LITERAL);
  80. }
  81. else if(Character.isDigit(c))
  82. {
  83. handleNumber(c);
  84. }
  85. else
  86. {
  87. handleSpecial(c);
  88. }
  89. }
  90. private void handleLiteral(int c, TokenType type)
  91. {
  92. StringBuilder sb = new StringBuilder();
  93. sb.append((char) c);
  94. while(true)
  95. {
  96. int data = peek();
  97. if(!Character.isLetterOrDigit(data) && data != '_')
  98. {
  99. break;
  100. }
  101. sb.append((char) data);
  102. next();
  103. }
  104. String s = sb.toString();
  105. switch(s)
  106. {
  107. case "if": add(IF); break;
  108. case "else": add(ELSE); break;
  109. case "elseif": add(ELSEIF); break;
  110. case "while": add(WHILE); break;
  111. case "try": add(TRY); break;
  112. case "catch": add(CATCH); break;
  113. case "for": add(FOR); break;
  114. case "function": add(FUNCTION); break;
  115. case "break": add(BREAK); break;
  116. case "continue": add(CONTINUE); break;
  117. case "return": add(RETURN); break;
  118. case "true": add(TRUE); break;
  119. case "false": add(FALSE); break;
  120. case "null": add(NULL); break;
  121. default: add(type, s);
  122. }
  123. }
  124. private void handleNumber(int c)
  125. {
  126. StringBuilder sb = new StringBuilder();
  127. sb.append((char) c);
  128. while(true)
  129. {
  130. int data = peek();
  131. if(!Character.isLetterOrDigit(data) && data != '.')
  132. {
  133. break;
  134. }
  135. next();
  136. sb.append((char) data);
  137. }
  138. add(NUMBER, Double.parseDouble(sb.toString()));
  139. }
  140. private void handleSpecial(int c)
  141. {
  142. switch(c)
  143. {
  144. case ' ':
  145. case '\t':
  146. case '\r': break;
  147. case '\n': line++; break;
  148. case '"': handleString(); break;
  149. case '(': add(OPEN_BRACKET); break;
  150. case ')': add(CLOSE_BRACKET); break;
  151. case '[': add(OPEN_SQUARE_BRACKET); break;
  152. case ']': add(CLOSE_SQUARE_BRACKET); break;
  153. case '{': add(OPEN_CURVED_BRACKET); break;
  154. case '}': add(CLOSE_CURVED_BRACKET); break;
  155. case '$': handleLiteral(c, LITERAL); break;
  156. case '@': handleLiteral(c, LABEL); break;
  157. case ';': add(SEMICOLON); break;
  158. case ',': add(COMMA); break;
  159. case '~': add(BIT_INVERT); break;
  160. case '+': add(next('=') ? ADD_SET : (next('+') ? INC : ADD)); break;
  161. case '-': add(next('=') ? SUB_SET : (next('-') ? DEC : SUB)); break;
  162. case '!': add(next('=') ? NOT_EQUAL : INVERT); break;
  163. case '=': add(next('=') ? EQUAL : SET); break;
  164. case '*': add(next('=') ? MUL_SET : MUL); break;
  165. case '/': handleSlash(); break;
  166. case '%': add(next('=') ? MOD_SET : MOD); break;
  167. case '&': add(next('=') ? BIT_AND_SET : (next('&') ? AND : BIT_AND)); break;
  168. case '|': add(next('=') ? BIT_OR_SET : (next('|') ? OR : BIT_OR)); break;
  169. case '^': add(next('=') ? BIT_XOR_SET : BIT_XOR); break;
  170. case '<': add('<', LEFT_SHIFT_SET, LEFT_SHIFT, LESS_EQUAL, LESS); break;
  171. case '>': add('>', RIGHT_SHIFT_SET, RIGHT_SHIFT, GREATER_EQUAL, GREATER); break;
  172. default: throw new PreScriptException("unknown token " + c, line);
  173. }
  174. }
  175. private void handleString()
  176. {
  177. StringBuilder sb = new StringBuilder();
  178. while(true)
  179. {
  180. int data = next();
  181. if(data == '"')
  182. {
  183. add(STRING, sb.toString());
  184. break;
  185. }
  186. if(data == '\n')
  187. {
  188. line++;
  189. }
  190. sb.append((char) data);
  191. }
  192. }
  193. private void handleSlash()
  194. {
  195. switch(peek())
  196. {
  197. case '/':
  198. next();
  199. handleOneLineComment();
  200. break;
  201. case '*':
  202. next();
  203. handleMultiLineComment();
  204. break;
  205. case '=':
  206. next();
  207. add(DIV_SET);
  208. break;
  209. default:
  210. add(DIV);
  211. }
  212. }
  213. private void handleOneLineComment()
  214. {
  215. while(true)
  216. {
  217. int data = next();
  218. if(data == -1 || data == '\n')
  219. {
  220. line++;
  221. break;
  222. }
  223. }
  224. }
  225. private void handleMultiLineComment()
  226. {
  227. int first;
  228. int sec = -1;
  229. while(true)
  230. {
  231. first = sec;
  232. sec = next();
  233. if(sec == -1 || (first == '*' && sec == '/'))
  234. {
  235. break;
  236. }
  237. if(sec == '\n')
  238. {
  239. line++;
  240. }
  241. }
  242. }
  243. }