Compiler.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. package me.hammerle.snuviscript.compiler;
  2. import me.hammerle.snuviscript.exceptions.PreScriptException;
  3. import me.hammerle.snuviscript.token.Token;
  4. import me.hammerle.snuviscript.token.TokenType;
  5. public class Compiler
  6. {
  7. private int index = 0;
  8. private Token[] tokens = null;
  9. public Compiler()
  10. {
  11. }
  12. public void checkSyntax(Token[] tokens)
  13. {
  14. this.tokens = tokens;
  15. index = 0;
  16. checkLine();
  17. }
  18. private Token consumeToken()
  19. {
  20. if(index >= tokens.length)
  21. {
  22. return null;
  23. }
  24. return tokens[index++];
  25. }
  26. private Token peekOrNullToken()
  27. {
  28. if(index >= tokens.length)
  29. {
  30. return null;
  31. }
  32. return tokens[index];
  33. }
  34. private Token peekToken()
  35. {
  36. if(index >= tokens.length)
  37. {
  38. throw new PreScriptException("missing token at end of file", -1);
  39. }
  40. return tokens[index];
  41. }
  42. private void consumeTokenAndCheck(TokenType... type)
  43. {
  44. Token t = consumeToken();
  45. if(t == null)
  46. {
  47. throw new PreScriptException("missing token at end of file " + type, -1);
  48. }
  49. for(TokenType ty : type)
  50. {
  51. if(ty == t.getType())
  52. {
  53. return;
  54. }
  55. }
  56. throw new PreScriptException("unexpected token " + t, t.getLine());
  57. }
  58. private void checkFunctionArguments()
  59. {
  60. TokenType type = peekToken().getType();
  61. if(type == TokenType.CLOSE_BRACKET)
  62. {
  63. consumeToken();
  64. return;
  65. }
  66. consumeTokenAndCheck(TokenType.LITERAL);
  67. while(true)
  68. {
  69. type = peekToken().getType();
  70. if(type == TokenType.CLOSE_BRACKET)
  71. {
  72. consumeToken();
  73. return;
  74. }
  75. consumeTokenAndCheck(TokenType.COMMA);
  76. consumeTokenAndCheck(TokenType.LITERAL);
  77. }
  78. }
  79. private void checkLine()
  80. {
  81. while(true)
  82. {
  83. Token t = peekOrNullToken();
  84. if(t == null || t.getType() == TokenType.CLOSE_CURVED_BRACKET)
  85. {
  86. break;
  87. }
  88. consumeToken();
  89. switch(t.getType())
  90. {
  91. case LITERAL:
  92. switch(t.getData().toString())
  93. {
  94. case "function":
  95. consumeTokenAndCheck(TokenType.LITERAL);
  96. consumeTokenAndCheck(TokenType.OPEN_BRACKET);
  97. checkFunctionArguments();
  98. consumeTokenAndCheck(TokenType.OPEN_CURVED_BRACKET);
  99. checkLine();
  100. consumeTokenAndCheck(TokenType.CLOSE_CURVED_BRACKET);
  101. break;
  102. case "for":
  103. consumeTokenAndCheck(TokenType.OPEN_BRACKET);
  104. checkArguments(TokenType.CLOSE_BRACKET);
  105. consumeTokenAndCheck(TokenType.OPEN_CURVED_BRACKET);
  106. checkLine();
  107. consumeTokenAndCheck(TokenType.CLOSE_CURVED_BRACKET);
  108. break;
  109. case "else":
  110. consumeTokenAndCheck(TokenType.OPEN_CURVED_BRACKET);
  111. checkLine();
  112. consumeTokenAndCheck(TokenType.CLOSE_CURVED_BRACKET);
  113. break;
  114. case "elseif":
  115. case "while":
  116. case "if":
  117. consumeTokenAndCheck(TokenType.OPEN_BRACKET);
  118. checkExpression();
  119. consumeTokenAndCheck(TokenType.CLOSE_BRACKET);
  120. consumeTokenAndCheck(TokenType.OPEN_CURVED_BRACKET);
  121. checkLine();
  122. consumeTokenAndCheck(TokenType.CLOSE_CURVED_BRACKET);
  123. break;
  124. case "try":
  125. consumeTokenAndCheck(TokenType.OPEN_CURVED_BRACKET);
  126. checkLine();
  127. consumeTokenAndCheck(TokenType.CLOSE_CURVED_BRACKET);
  128. Token token = consumeToken();
  129. if(token.getType() != TokenType.LITERAL || !token.getData().equals("catch"))
  130. {
  131. throw new PreScriptException("try without catch", token.getLine());
  132. }
  133. consumeTokenAndCheck(TokenType.OPEN_CURVED_BRACKET);
  134. checkLine();
  135. consumeTokenAndCheck(TokenType.CLOSE_CURVED_BRACKET);
  136. break;
  137. case "continue":
  138. case "break":
  139. consumeTokenAndCheck(TokenType.SEMICOLON);
  140. break;
  141. case "return":
  142. if(peekToken().getType() == TokenType.SEMICOLON)
  143. {
  144. consumeToken();
  145. }
  146. else
  147. {
  148. checkExpression();
  149. consumeTokenAndCheck(TokenType.SEMICOLON);
  150. }
  151. break;
  152. default:
  153. checkAfterLiteral(true);
  154. consumeTokenAndCheck(TokenType.SEMICOLON);
  155. }
  156. break;
  157. case OPEN_CURVED_BRACKET:
  158. checkLine();
  159. consumeTokenAndCheck(TokenType.CLOSE_CURVED_BRACKET);
  160. break;
  161. /*case DOLLAR:
  162. checkVariable();
  163. checkVariableOperation(true);
  164. consumeTokenAndCheck(TokenType.SEMICOLON);
  165. break;*/
  166. case LABEL:
  167. consumeTokenAndCheck(TokenType.LITERAL, TokenType.NUMBER);
  168. break;
  169. case SEMICOLON:
  170. break;
  171. case INC:
  172. case DEC:
  173. Token token = peekToken();
  174. //if(token.getType() == TokenType.DOLLAR)
  175. {
  176. consumeToken();
  177. }
  178. checkVariable();
  179. consumeTokenAndCheck(TokenType.SEMICOLON);
  180. break;
  181. default:
  182. throw new PreScriptException("unexpected token " + t, t.getLine());
  183. }
  184. }
  185. }
  186. private void checkVariable()
  187. {
  188. consumeTokenAndCheck(TokenType.LITERAL);
  189. Token t = peekToken();
  190. if(t.getType() == TokenType.OPEN_SQUARE_BRACKET)
  191. {
  192. consumeToken();
  193. checkArguments(TokenType.CLOSE_SQUARE_BRACKET);
  194. }
  195. }
  196. private void checkAfterLiteral(boolean line)
  197. {
  198. Token t = peekToken();
  199. switch(t.getType())
  200. {
  201. case OPEN_BRACKET:
  202. consumeToken();
  203. checkArguments(TokenType.CLOSE_BRACKET);
  204. if(!line)
  205. {
  206. checkCalc();
  207. }
  208. return;
  209. case OPEN_SQUARE_BRACKET:
  210. consumeToken();
  211. checkArguments(TokenType.CLOSE_SQUARE_BRACKET);
  212. checkVariableOperation(line);
  213. return;
  214. case INC:
  215. case DEC:
  216. consumeToken();
  217. checkCalc();
  218. return;
  219. case SET:
  220. case ADD_SET:
  221. case SUB_SET:
  222. case MUL_SET:
  223. case DIV_SET:
  224. case MOD_SET:
  225. case LEFT_SHIFT_SET:
  226. case RIGHT_SHIFT_SET:
  227. case BIT_AND_SET:
  228. case BIT_XOR_SET:
  229. case BIT_OR_SET:
  230. consumeToken();
  231. checkExpression();
  232. return;
  233. default:
  234. if(line)
  235. {
  236. throw new PreScriptException("unexpected token " + t, t.getLine());
  237. }
  238. }
  239. checkCalc();
  240. }
  241. private void checkVariableOperation(boolean line)
  242. {
  243. Token t = peekToken();
  244. switch(t.getType())
  245. {
  246. case INC:
  247. case DEC:
  248. case SET:
  249. case ADD_SET:
  250. case SUB_SET:
  251. case MUL_SET:
  252. case DIV_SET:
  253. case MOD_SET:
  254. case LEFT_SHIFT_SET:
  255. case RIGHT_SHIFT_SET:
  256. case BIT_AND_SET:
  257. case BIT_XOR_SET:
  258. case BIT_OR_SET:
  259. consumeToken();
  260. checkExpression();
  261. break;
  262. default:
  263. if(line)
  264. {
  265. throw new PreScriptException("unexpected token " + t, t.getLine());
  266. }
  267. else
  268. {
  269. checkCalc();
  270. }
  271. }
  272. }
  273. private void checkCalc()
  274. {
  275. Token t = peekToken();
  276. switch(t.getType())
  277. {
  278. case MUL:
  279. case DIV:
  280. case MOD:
  281. case ADD:
  282. case SUB:
  283. case LEFT_SHIFT:
  284. case RIGHT_SHIFT:
  285. case LESS:
  286. case LESS_EQUAL:
  287. case GREATER:
  288. case GREATER_EQUAL:
  289. case EQUAL:
  290. case NOT_EQUAL:
  291. case BIT_AND:
  292. case BIT_XOR:
  293. case BIT_OR:
  294. case AND:
  295. case OR:
  296. consumeToken();
  297. checkExpression();
  298. break;
  299. }
  300. }
  301. private void checkArguments(TokenType end)
  302. {
  303. Token t = peekToken();
  304. if(t.getType() == end)
  305. {
  306. consumeToken();
  307. return;
  308. }
  309. checkExpression();
  310. while(true)
  311. {
  312. t = peekToken();
  313. if(t.getType() == end)
  314. {
  315. consumeToken();
  316. return;
  317. }
  318. consumeTokenAndCheck(TokenType.COMMA);
  319. checkExpression();
  320. }
  321. }
  322. private void checkExpression()
  323. {
  324. Token t = consumeToken();
  325. switch(t.getType())
  326. {
  327. case SUB:
  328. checkExpression();
  329. break;
  330. case NUMBER:
  331. case STRING:
  332. checkCalc();
  333. break;
  334. case LITERAL:
  335. checkAfterLiteral(false);
  336. break;
  337. case OPEN_BRACKET:
  338. checkExpression();
  339. consumeTokenAndCheck(TokenType.CLOSE_BRACKET);
  340. checkCalc();
  341. break;
  342. /*case DOLLAR:
  343. checkVariable();
  344. checkVariableOperation(false);
  345. break;*/
  346. case LABEL:
  347. consumeTokenAndCheck(TokenType.LITERAL);
  348. break;
  349. case INC:
  350. case DEC:
  351. Token token = peekToken();
  352. //if(token.getType() == TokenType.DOLLAR)
  353. {
  354. consumeToken();
  355. }
  356. checkVariable();
  357. checkCalc();
  358. break;
  359. case INVERT:
  360. case BIT_INVERT:
  361. checkExpression();
  362. break;
  363. default:
  364. throw new PreScriptException("unexpected token " + t, t.getLine());
  365. }
  366. }
  367. }