fork download
  1. import java.util.*;
  2. import java.lang.*;
  3. import java.io.*;
  4. import java.util.regex.*;
  5.  
  6. class Ideone
  7. {
  8. public static void main (String[] args) throws java.lang.Exception
  9. {
  10. try {
  11. Excutor excutor = new Excutor();
  12. String line;
  13. while ((line = in.readLine()) != null) {
  14. try {
  15. List<Token> tokens = Tokenizer.tokenize(line);
  16. if (excutor.doEditorCommand(tokens) < 0) {
  17. break;
  18. }
  19. } catch (SyntaxError er) {
  20. System.out.println(er);
  21. }
  22. }
  23. // System.out.println(excutor);
  24. } catch (Exception ex) {
  25. System.out.println(ex);
  26. }
  27.  
  28. }
  29. }
  30.  
  31. enum TokenType
  32. {
  33. INT, DBL, STR, NAME, SYMBL, SHARP, SEMICOLON,
  34. OP_BRKT, CL_BRKT, COMMA, COLON, UNKNOWN
  35. }
  36.  
  37. final class Token
  38. {
  39. final TokenType type;
  40. final String token;
  41. public Token(TokenType type, String token)
  42. {
  43. this.type = type;
  44. this.token = token;
  45. }
  46. public TokenType getType() { return type; }
  47. public String getToken() { return token; }
  48. @Override
  49. public String toString()
  50. {
  51. return "[" + type + " : " + token + "]";
  52. }
  53.  
  54. public boolean isInt() { return TokenType.INT.equals(type); }
  55. public boolean isStr() { return TokenType.STR.equals(type); }
  56. public boolean isDbl() { return TokenType.DBL.equals(type); }
  57. public boolean isName() { return TokenType.NAME.equals(type); }
  58. public boolean isSymbl() { return TokenType.SYMBL.equals(type); }
  59. public boolean isOpBrkt() { return TokenType.OP_BRKT.equals(type); }
  60. public boolean isClBrkt() { return TokenType.CL_BRKT.equals(type); }
  61. public boolean isColon() { return TokenType.COLON.equals(type); }
  62. public boolean isSemiColon() { return TokenType.SEMICOLON.equals(type); }
  63. public boolean isComma() { return TokenType.COMMA.equals(type); }
  64. public boolean isSharp() { return TokenType.SHARP.equals(type); }
  65. }
  66.  
  67. class SyntaxError extends java.lang.Exception
  68. {
  69. public SyntaxError(String msg) { super(msg); }
  70. public SyntaxError(Throwable ex) { super(ex); }
  71. public SyntaxError(List<Token> tokens, int index)
  72. {
  73. super("token index(" + index + "): " + tokens.toString());
  74. }
  75. }
  76.  
  77. final class TokenError extends SyntaxError
  78. {
  79. public TokenError(String line) { super(line); }
  80. }
  81.  
  82. final class Tokenizer
  83. {
  84. private static Pattern p_space = Pattern.compile("^\\s+");
  85. private static Pattern p_int = Pattern.compile("^\\d+");
  86. private static Pattern p_dbl = Pattern.compile("^\\d*\\.\\d+");
  87. private static Pattern p_str = Pattern.compile("^\"(\"\"|[^\"])*\"");
  88. private static Pattern p_name = Pattern.compile("^[A-Za-z][A-Za-z0-9]*\\$?");
  89. private static Pattern p_symbl = Pattern.compile("^(>=|<=|<>|[=<>+\\*/-])");
  90.  
  91. public static List<Token> tokenize(String line) throws TokenError
  92. {
  93. List<Token> list = new ArrayList<Token>();
  94. Matcher m = null;
  95. TokenType type = null;
  96. String token = null;
  97. int offset = 0;
  98.  
  99. while (line.length() > 0) {
  100. if ((m = p_space.matcher(line)).lookingAt()) {
  101. line = line.substring(m.end());
  102. continue;
  103. } else if ((m = p_dbl.matcher(line)).lookingAt()) {
  104. type = TokenType.DBL;
  105. } else if ((m = p_int.matcher(line)).lookingAt()) {
  106. type = TokenType.INT;
  107. } else if ((m = p_str.matcher(line)).lookingAt()) {
  108. type = TokenType.STR;
  109. } else if ((m = p_name.matcher(line)).lookingAt()) {
  110. type = TokenType.NAME;
  111. } else if ((m = p_symbl.matcher(line)).lookingAt()) {
  112. type = TokenType.SYMBL;
  113. } else {
  114. m = null;
  115. offset = 1;
  116. if (line.startsWith(token = "(")) {
  117. type = TokenType.OP_BRKT;
  118. } else if (line.startsWith(token = ")")) {
  119. type = TokenType.CL_BRKT;
  120. } else if (line.startsWith(token = ":")) {
  121. type = TokenType.COLON;
  122. } else if (line.startsWith(token = ",")) {
  123. type = TokenType.COMMA;
  124. } else if (line.startsWith(token = "#")) {
  125. type = TokenType.SHARP;
  126. } else if (line.startsWith(token = ";")) {
  127. type = TokenType.SEMICOLON;
  128. } else {
  129. throw new TokenError(line);
  130. }
  131. }
  132. if (m != null) {
  133. token = m.group();
  134. if (TokenType.NAME.equals(type)) {
  135. token = token.toUpperCase();
  136. }
  137. offset = m.end();
  138. }
  139. list.add(new Token(type, token));
  140. line = line.substring(offset);
  141. }
  142. return list;
  143. }
  144. }
  145.  
  146. final class ExcuteError extends SyntaxError
  147. {
  148. public ExcuteError(Throwable ex) { super(ex); }
  149. public ExcuteError(String msg) { super(msg); }
  150. }
  151.  
  152. class VarArray<T>
  153. {
  154.  
  155. }
  156.  
  157. enum ResultType
  158. {
  159. INT, DBL, STR
  160. }
  161.  
  162. class Result
  163. {
  164. private int offset;
  165. private int intvalue = 0;
  166. private double dblvalue = 0;
  167. private String strvalue = null;
  168. private ResultType type;
  169.  
  170. public ResultType getType()
  171. {
  172. return type;
  173. }
  174.  
  175. public int getOffset()
  176. {
  177. return offset;
  178. }
  179.  
  180. public Number getNumValue()
  181. {
  182. if (ResultType.INT.equals(type)) {
  183. return Integer.valueOf(intvalue);
  184. } else if (ResultType.DBL.equals(type)) {
  185. return Double.valueOf(dblvalue);
  186. } else {
  187. return null;
  188. }
  189. }
  190. public String getStrValue()
  191. {
  192. return strvalue;
  193. }
  194. }
  195.  
  196. final class Excutor
  197. {
  198. private NavigableMap<Integer, List<Token>> program = new TreeMap<Integer, List<Token>>();
  199.  
  200. private Map<String, VarArray<String>> strarrs = new HashMap<String, VarArray<String>>();
  201. private Map<String, VarArray<Number>> numarrs = new HashMap<String, VarArray<Number>>();
  202. private Map<String, String> strvars = new HashMap<String, String>();
  203. private Map<String, Number> numvars = new HashMap<String, Number>();
  204.  
  205. private Integer programcounter = null;
  206. private Deque<Integer> programcounterstack = new ArrayDeque<Integer>();
  207.  
  208. private int arraybase = 0;
  209. private boolean jumpflag = false;
  210.  
  211. public Excutor() {}
  212.  
  213. private void printLine(Integer linenum, List<Token> tokens)
  214. {
  215. System.out.printf("%05d ", linenum.intValue());
  216. TokenType before = null, type;
  217. for (int i = 1; i < tokens.size(); i++) {
  218. Token token = tokens.get(i);
  219. type = token.getType();
  220. if (TokenType.NAME.equals(before)) {
  221. switch (type) {
  222. case NAME:
  223. case INT:
  224. case DBL:
  225. case SHARP:
  226. case STR:
  227. System.out.print(' ');
  228. break;
  229. default:
  230. break;
  231. }
  232. }
  233. System.out.print(tokens.get(i).getToken());
  234. before = type;
  235. }
  236. System.out.println();
  237. }
  238.  
  239. private Result calc(List<Token> tokens, int index) throws SyntaxError
  240. {
  241. if (index >= tokens.size()) {
  242. throw new SyntaxError(tokens, index);
  243. }
  244.  
  245. Token cur = tokens.get(index);
  246. TokenType type = cur.getType();
  247. String token = cur.getToken();
  248.  
  249. switch (type) {
  250. case INT:
  251. case DBL:
  252. case STR:
  253. case SYMBL:
  254. case OP_BRKT:
  255. break;
  256. default:
  257. break;
  258. }
  259.  
  260. // 最初のトークンから始まる項を取得しスタックに上げ
  261. // その項の次のトークンである演算子をスタックに上げ
  262. // その演算子の次のトークンから始まる項をスタックに上げ
  263. // その次に演算子が来たら演算子の優先順位が
  264. // ・高かったらその次の項の読み出し
  265. // ・低かったら スタックにある演算子で演算
  266. //
  267.  
  268. return null;
  269. }
  270.  
  271. public int doEditorCommand(List<Token> tokens) throws SyntaxError
  272. {
  273. if (tokens == null || tokens.isEmpty()) {
  274. return 0;
  275. }
  276.  
  277. Token first = tokens.get(0);
  278. String token = first.getToken();
  279. TokenType type = first.getType();
  280.  
  281. if (TokenType.INT.equals(type)) {
  282. Integer tmpint = Integer.valueOf(token);
  283. if (tmpint.intValue() < 1) {
  284. throw new SyntaxError(token);
  285. }
  286. program.put(tmpint, tokens);
  287. return 0;
  288. } else if (TokenType.NAME.equals(type) == false) {
  289. throw new ExcuteError(token);
  290. }
  291. switch (token) {
  292. case "CONT": // プログラムの再開
  293. case "EXIT": // インタプリタの終了
  294. return -1;
  295. case "LIST": // プログラムの表示
  296. do_list(tokens);
  297. break;
  298. case "LOAD": // プログラムのロード
  299. case "NEW": // プログラムと変数の全消去
  300. case "RENUM": // プログラムの行番号再割り当て
  301. break;
  302. case "RUN": // プログラムの実行
  303. do_run(tokens);
  304. break;
  305. case "SAVE": // プログラムの保存
  306. break;
  307. default:
  308. excute(tokens, 0);
  309. break;
  310. }
  311. System.out.println("Ok");
  312. return 0;
  313. }
  314.  
  315. private void do_list(List<Token> tokens) throws SyntaxError
  316. {
  317. Integer start = null;
  318. Integer end = null;
  319. Token first, second, third;
  320. Map<Integer, List<Token>> list = null;
  321. try {
  322. switch (tokens.size()) {
  323. case 1:
  324. list = program;
  325. break;
  326. case 2:
  327. first = tokens.get(1);
  328. if (TokenType.INT.equals(first.getType()) == false) {
  329. throw new SyntaxError(tokens ,1);
  330. }
  331. start = Integer.valueOf(first.getToken());
  332. if (start.intValue() < 1) {
  333. throw new SyntaxError(tokens ,1);
  334. }
  335. list = program.tailMap(start);
  336. break;
  337. case 3:
  338. if ("-".equals(tokens.get(1).getToken()) == false) {
  339. throw new SyntaxError(tokens ,1);
  340. }
  341. second = tokens.get(2);
  342. if (TokenType.INT.equals(second.getType()) == false) {
  343. throw new SyntaxError(tokens ,2);
  344. }
  345. end = Integer.valueOf(second.getToken());
  346. if (end.intValue() < 1) {
  347. throw new SyntaxError(tokens ,2);
  348. }
  349. list = program.headMap(end, true);
  350. break;
  351. case 4:
  352. first = tokens.get(1);
  353. if (TokenType.INT.equals(first.getType()) == false) {
  354. throw new SyntaxError(tokens ,1);
  355. }
  356. start = Integer.valueOf(first.getToken());
  357. if (start.intValue() < 1) {
  358. throw new SyntaxError(tokens ,1);
  359. }
  360. if ("-".equals(tokens.get(2).getToken()) == false) {
  361. throw new SyntaxError(tokens ,2);
  362. }
  363. third = tokens.get(3);
  364. if (TokenType.INT.equals(third.getType()) == false) {
  365. throw new SyntaxError(tokens ,3);
  366. }
  367. end = Integer.valueOf(third.getToken());
  368. if (end.intValue() < 1) {
  369. throw new SyntaxError(tokens ,3);
  370. }
  371. list = program.subMap(start, true, end, true);
  372. break;
  373. default:
  374. throw new SyntaxError(tokens, 0);
  375. }
  376. } catch (SyntaxError er) {
  377. throw er;
  378. } catch (Exception ex) {
  379. throw new ExcuteError(ex);
  380. }
  381.  
  382. if (list == null) {
  383. return;
  384. }
  385.  
  386. for (Integer key: list.keySet()) {
  387. printLine(key, list.get(key));
  388. }
  389.  
  390. }
  391.  
  392. private void do_run(List<Token> tokens) throws SyntaxError
  393. {
  394. switch (tokens.size()) {
  395. case 1:
  396. programcounter = program.ceilingKey(Integer.valueOf(1));
  397. if (programcounter == null) {
  398. throw new SyntaxError("Program is not found");
  399. }
  400. break;
  401. case 2:
  402. Token first = tokens.get(1);
  403. if (TokenType.INT.equals(first.getType()) == false) {
  404. throw new SyntaxError("Illegal Argument");
  405. }
  406. programcounter = Integer.valueOf(first.getToken());
  407. if (programcounter.intValue() < 1) {
  408. throw new SyntaxError("Wrong Line Number");
  409. }
  410. if (program.containsKey(programcounter) == false) {
  411. throw new SyntaxError("Not found Line Number");
  412. }
  413. break;
  414. default:
  415. throw new SyntaxError("Illegal Arguments");
  416. }
  417.  
  418. List<Token> line = null;
  419. try {
  420. while (programcounter != null) {
  421. line = program.get(programcounter);
  422. excute(line, 1);
  423. if (jumpflag == false) {
  424. programcounter = program.higherKey(programcounter);
  425. } else {
  426. jumpflag = false;
  427. }
  428. }
  429. } catch (SyntaxError er) {
  430. System.out.println(line);
  431. throw er;
  432. }
  433.  
  434. }
  435.  
  436. private int excute(List<Token> tokens, int index) throws SyntaxError
  437. {
  438. if (index < 0 || index >= tokens.size()) {
  439. return tokens.size();
  440. }
  441. Token first = tokens.get(index);
  442. TokenType type = first.getType();
  443.  
  444. while (TokenType.COLON.equals(type)) {
  445. index++;
  446. if (index == tokens.size()) {
  447. return index;
  448. }
  449. first = tokens.get(index);
  450. type = first.getType();
  451. }
  452.  
  453. if (TokenType.NAME.equals(type) == false) {
  454. throw new SyntaxError(first.toString());
  455. }
  456. String cmd = first.getToken();
  457. int offset = index;
  458. switch (cmd) {
  459. case "BASE": // 配列の下限(0/1)の設定
  460. offset = cmd_base(tokens, index + 1);
  461. break;
  462. case "BREAK": // FORループの脱出
  463. case "DATA": // データの列挙
  464. case "DIM": // 配列変数の宣言
  465. case "ELSE": // IF文のELSE節の開始
  466. case "END": // プログラムの終了
  467. case "FILE": // ファイルの割り当て
  468. case "FOR": // 繰り返し
  469. break;
  470. case "GO": // GOTOの分割トークン
  471. if (index + 2 >= tokens.size()) {
  472. throw new SyntaxError(tokens, index);
  473. }
  474. if ("TO".equals(tokens.get(index + 1).getToken()) == false) {
  475. throw new SyntaxError(tokens, index);
  476. }
  477. offset = cmd_goto(tokens, index + 2);
  478. break;
  479. case "GOTO": // ジャンプ
  480. offset = cmd_goto(tokens, index + 1);
  481. break;
  482. case "GOSUB": // サブルーチンジャンプ
  483. offset = cmd_gosub(tokens, index + 1);
  484. break;
  485. case "IF": // 条件節
  486. case "INPUT": // キーボードからの値の入力
  487. break;
  488. case "LET": // 変数への代入
  489. offset = cmd_let(tokens, index + 1);
  490. break;
  491. case "NEXT": // FOR文の末端
  492. case "PRINT": // 画面へ値を出力
  493. break;
  494. case "REM": // コメント行
  495. offset = tokens.size();
  496. break;
  497. case "RESTORE": // データ・ファイルの読み込み位置のリセット
  498. break;
  499. case "RETURN": // サブルーチンからの脱出
  500. offset = cmd_return(tokens, index);
  501. break;
  502. case "STOP": // プログラムの中断
  503. break;
  504. default:
  505. offset = cmd_let(tokens, index);
  506. break;
  507. }
  508. return offset;
  509. }
  510.  
  511. @Override
  512. public String toString()
  513. {
  514. return program.toString().replaceAll("(\\d+=\\[\\[)", "\n$1");
  515. }
  516.  
  517. private int cmd_goto(List<Token> tokens, int index) throws SyntaxError
  518. {
  519. if (index >= tokens.size()) {
  520. throw new SyntaxError(tokens, index);
  521. }
  522. if (index + 1 < tokens.size()) {
  523. if (TokenType.COLON.equals(tokens.get(index + 1).getType()) == false) {
  524. throw new SyntaxError(tokens, index + 1);
  525. }
  526. }
  527. Token first = tokens.get(index);
  528. if (TokenType.INT.equals(first.getType()) == false) {
  529. throw new SyntaxError(tokens, index);
  530. }
  531. Integer next = Integer.valueOf(first.getToken());
  532. if (program.containsKey(next) == false) {
  533. throw new SyntaxError(tokens, index);
  534. }
  535. programcounter = next;
  536. jumpflag = true;
  537. return tokens.size();
  538. }
  539.  
  540. private int cmd_gosub(List<Token> tokens, int index) throws SyntaxError
  541. {
  542. if (index >= tokens.size()) {
  543. throw new SyntaxError(tokens, index);
  544. }
  545. if (index + 1 < tokens.size()) {
  546. if (TokenType.COLON.equals(tokens.get(index + 1).getType()) == false) {
  547. throw new SyntaxError(tokens, index + 1);
  548. }
  549. }
  550. Token first = tokens.get(index);
  551. if (TokenType.INT.equals(first.getType()) == false) {
  552. throw new SyntaxError(tokens, index);
  553. }
  554. Integer next = Integer.valueOf(first.getToken());
  555. if (program.containsKey(next) == false) {
  556. throw new SyntaxError(tokens, index);
  557. }
  558. try {
  559. programcounterstack.push(programcounter);
  560. programcounter = next;
  561. jumpflag = true;
  562. return tokens.size();
  563. } catch (Exception ex) {
  564. throw new ExcuteError(ex);
  565. }
  566. }
  567.  
  568. private int cmd_return(List<Token> tokens, int index) throws SyntaxError
  569. {
  570. if (index < tokens.size()) {
  571. if (TokenType.COLON.equals(tokens.get(index).getType()) == false) {
  572. throw new SyntaxError(tokens, index);
  573. }
  574. }
  575. try {
  576. Integer back = programcounterstack.pop();
  577. programcounter = program.higherKey(back);
  578. jumpflag = true;
  579. return tokens.size();
  580. } catch (Exception ex) {
  581. throw new ExcuteError(ex);
  582. }
  583. }
  584.  
  585.  
  586. private int cmd_base(List<Token> tokens, int index) throws SyntaxError
  587. {
  588. try {
  589. Token first = tokens.get(index);
  590. if (TokenType.INT.equals(first.getType()) == false) {
  591. throw new SyntaxError(tokens, index);
  592. }
  593. int tmpint = Integer.parseInt(first.getToken());
  594. if (tmpint != 0 && tmpint != 1) {
  595. throw new SyntaxError(tokens, index + 1);
  596. }
  597. arraybase = tmpint;
  598. return excute(tokens, index + 1);
  599. } catch (SyntaxError er) {
  600. throw er;
  601. } catch (Exception ex) {
  602. throw new ExcuteError(ex);
  603. }
  604. }
  605.  
  606. private int cmd_let(List<Token> tokens, int index) throws SyntaxError
  607. {
  608. try {
  609. Token first = tokens.get(index);
  610. String name = first.getToken();
  611. // if (checkKeyword(name)) // 予約語チェック
  612. // throw new SyntaxError("Wrong variable name: " + name);
  613. index++;
  614. if (name.lastIndexOf("$") > 0) {
  615. if (strarrs.containsKey(name)) {
  616. if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
  617. throw new SyntaxError(tokens, index);
  618. }
  619. } else {
  620. if ("=".equals(tokens.get(index).getToken()) == false) {
  621. throw new SyntaxError(tokens, index);
  622. }
  623. index++;
  624. // Result result = calc(tokens, index);
  625. // if (result.getType() != "STRING")
  626. // throw new ExcuteError();
  627. // offset = result.getOffset();
  628. // strvars.put(name, result.getStrValue());
  629. }
  630. } else {
  631. if (numarrs.containsKey(name)) {
  632. if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
  633. throw new SyntaxError(tokens, index);
  634. }
  635. } else {
  636. if ("=".equals(tokens.get(index).getToken()) == false) {
  637. throw new SyntaxError(tokens ,index);
  638. }
  639. // Result result = calc(tokens, index);
  640. // if (result.getType() != "NUMBER")
  641. // throw new ExcuteError();
  642. // offset = result.getOffset();
  643. // numvars.put(name, result.getNumValue());
  644. }
  645. }
  646. // return excute(tokens, index);
  647. return tokens.size();
  648. } catch (SyntaxError er) {
  649. throw er;
  650. } catch (Exception ex) {
  651. ex.printStackTrace();
  652. throw new ExcuteError(tokens.toString());
  653. }
  654.  
  655. }
  656.  
  657. }
Success #stdin #stdout 0.1s 380352KB
stdin
00010 LET J4=1
00030 PRINT
00100 BASE 0
00110 LET X=0
00120 LET J=0
00130 LET K=0
00140 X1=0
00150 LET X3=0
00160 LET J9=RND(CLK(J9))
00170 DIM C(7),C$(7),W(100),D(50,50),P(100),I$(100),B(100,6),B$(100)
00180 DIM E(100),F(100),X5(100),X6(100),X2(100),X4(100)
00190 LET G=INT(RND(0)*24+2)
00200 LET H=INT(RND(0)*24+2)
00210 FILE #1="DNG1"
00220 FILE #2="DNG2",#3="DNG3",#4="DNG4",#5="DNG5",#6="DNG6"
00230 RESTORE #4
00240 FILE #7="GMSTR"
00245 RESTORE #7
00250 RESTORE #1
00260 RESTORE #2
00261 RESTORE #3
00262 RESTORE #4
00263 RESTORE #5
00264 RESTORE #6
00270 DATA "STR","DEX","CON","CHAR","WIS","INT","GOLD"
list 100-150
run
stdout
00100 BASE 0
00110 LET X=0
00120 LET J=0
00130 LET K=0
00140 X1=0
00150 LET X3=0
Ok
Ok