fork(1) download
  1. import java.util.*;
  2. import java.lang.*;
  3. import java.io.*;
  4. import java.util.regex.*;
  5.  
  6. class Basic
  7. {
  8. public static void main (String[] args) throws java.lang.Exception
  9. {
  10. System.out.println("*** BASIC Interpreter ***");
  11. System.out.println("Ok");
  12. System.out.println("");
  13. try {
  14. Excutor excutor = new Excutor();
  15. String line;
  16. while ((line = in.readLine()) != null) {
  17. try {
  18. List<Token> tokens = Tokenizer.tokenize(line);
  19. if (excutor.doEditorCommand(tokens) < 0) {
  20. break;
  21. }
  22. } catch (SyntaxError er) {
  23. System.out.println(er);
  24. }
  25. }
  26. // System.out.println(excutor);
  27. } catch (Exception ex) {
  28. System.out.println(ex);
  29. }
  30.  
  31. }
  32. }
  33.  
  34. enum TokenType
  35. {
  36. INT, DBL, STR, NAME, SYMBL, SHARP, SEMICOLON,
  37. OP_BRKT, CL_BRKT, COMMA, COLON, UNKNOWN
  38. }
  39.  
  40. final class Token
  41. {
  42. final TokenType type;
  43. final String token;
  44. public Token(TokenType type, String token)
  45. {
  46. this.type = type;
  47. this.token = token;
  48. }
  49. public TokenType getType() { return type; }
  50. public String getToken() { return token; }
  51. @Override
  52. public String toString()
  53. {
  54. return "[" + type + " : " + token + "]";
  55. }
  56.  
  57. public boolean isInt() { return TokenType.INT.equals(type); }
  58. public boolean isStr() { return TokenType.STR.equals(type); }
  59. public boolean isDbl() { return TokenType.DBL.equals(type); }
  60. public boolean isName() { return TokenType.NAME.equals(type); }
  61. public boolean isSymbl() { return TokenType.SYMBL.equals(type); }
  62. public boolean isOpBrkt() { return TokenType.OP_BRKT.equals(type); }
  63. public boolean isClBrkt() { return TokenType.CL_BRKT.equals(type); }
  64. public boolean isColon() { return TokenType.COLON.equals(type); }
  65. public boolean isSemiColon() { return TokenType.SEMICOLON.equals(type); }
  66. public boolean isComma() { return TokenType.COMMA.equals(type); }
  67. public boolean isSharp() { return TokenType.SHARP.equals(type); }
  68. }
  69.  
  70. class SyntaxError extends java.lang.Exception
  71. {
  72. public SyntaxError(String msg) { super(msg); }
  73. public SyntaxError(Throwable ex) { super(ex); }
  74. public SyntaxError(List<Token> tokens, int index)
  75. {
  76. super("token index(" + index + "): " + tokens.toString());
  77. }
  78. }
  79.  
  80. final class TokenError extends SyntaxError
  81. {
  82. public TokenError(String line) { super(line); }
  83. }
  84.  
  85. final class Tokenizer
  86. {
  87. private static Pattern p_space = Pattern.compile("^\\s+");
  88. private static Pattern p_int = Pattern.compile("^\\d+");
  89. private static Pattern p_dbl = Pattern.compile("^\\d*\\.\\d+");
  90. private static Pattern p_str = Pattern.compile("^\"(\"\"|[^\"])*\"");
  91. private static Pattern p_name = Pattern.compile("^[A-Za-z][A-Za-z0-9]*\\$?");
  92. private static Pattern p_symbl = Pattern.compile("^(>=|<=|<>|[=<>+\\*/-])");
  93.  
  94. public static List<Token> tokenize(String line) throws TokenError
  95. {
  96. List<Token> list = new ArrayList<Token>();
  97. Matcher m = null;
  98. TokenType type = null;
  99. String token = null;
  100. int offset = 0;
  101.  
  102. while (line.length() > 0) {
  103. if ((m = p_space.matcher(line)).lookingAt()) {
  104. line = line.substring(m.end());
  105. continue;
  106. } else if ((m = p_dbl.matcher(line)).lookingAt()) {
  107. type = TokenType.DBL;
  108. } else if ((m = p_int.matcher(line)).lookingAt()) {
  109. type = TokenType.INT;
  110. } else if ((m = p_str.matcher(line)).lookingAt()) {
  111. type = TokenType.STR;
  112. } else if ((m = p_name.matcher(line)).lookingAt()) {
  113. type = TokenType.NAME;
  114. } else if ((m = p_symbl.matcher(line)).lookingAt()) {
  115. type = TokenType.SYMBL;
  116. } else {
  117. m = null;
  118. offset = 1;
  119. if (line.startsWith(token = "(")) {
  120. type = TokenType.OP_BRKT;
  121. } else if (line.startsWith(token = ")")) {
  122. type = TokenType.CL_BRKT;
  123. } else if (line.startsWith(token = ":")) {
  124. type = TokenType.COLON;
  125. } else if (line.startsWith(token = ",")) {
  126. type = TokenType.COMMA;
  127. } else if (line.startsWith(token = "#")) {
  128. type = TokenType.SHARP;
  129. } else if (line.startsWith(token = ";")) {
  130. type = TokenType.SEMICOLON;
  131. } else {
  132. throw new TokenError(line);
  133. }
  134. }
  135. if (m != null) {
  136. token = m.group();
  137. if (TokenType.NAME.equals(type)) {
  138. token = token.toUpperCase();
  139. }
  140. offset = m.end();
  141. }
  142. list.add(new Token(type, token));
  143. line = line.substring(offset);
  144. }
  145. return list;
  146. }
  147. }
  148.  
  149. final class ExcuteError extends SyntaxError
  150. {
  151. public ExcuteError(Throwable ex) { super(ex); }
  152. public ExcuteError(String msg) { super(msg); }
  153. }
  154.  
  155. class VarArray<T>
  156. {
  157.  
  158. }
  159.  
  160. enum ResultType
  161. {
  162. INT, DBL, STR, EOL, UNKNOWN
  163. }
  164.  
  165. class Result
  166. {
  167. public static final Result getTrue() {
  168. return new Result((int)-1);
  169. }
  170. public static final Result getFalse() {
  171. return new Result((int)0);
  172. }
  173. public static final Result getBool(boolean bool) {
  174. return bool ? getTrue() : getFalse();
  175. }
  176.  
  177. private int offset;
  178. private int intvalue = 0;
  179. private double dblvalue = 0;
  180. private String strvalue = null;
  181. private ResultType type;
  182.  
  183. Result() {
  184. type = ResultType.EOL;
  185. }
  186.  
  187. static Result getEOL(int offset) {
  188. Result temp = new Result();
  189. temp.offset = offset;
  190. return temp;
  191. }
  192.  
  193. Result(int value) {
  194. intvalue = value;
  195. type = ResultType.INT;
  196. }
  197.  
  198.  
  199. Result(double value) {
  200. dblvalue = value;
  201. type = ResultType.DBL;
  202. }
  203.  
  204.  
  205. Result(Number value) {
  206. if (Integer.class.equals(value.getClass())) {
  207. intvalue = value.intValue();
  208. type = ResultType.INT;
  209. } else if (Double.class.equals(value.getClass())) {
  210. dblvalue = value.doubleValue();
  211. type = ResultType.DBL;
  212. } else {
  213. type = ResultType.UNKNOWN;
  214. }
  215. }
  216.  
  217. Result(String value) {
  218. strvalue = value;
  219. type = ResultType.STR;
  220. }
  221.  
  222. Result(int value, int offset) {
  223. this(value);
  224. this.offset = offset;
  225. }
  226.  
  227. Result(double value, int offset) {
  228. this(value);
  229. this.offset = offset;
  230. }
  231.  
  232. Result(Number value, int offset) {
  233. this(value);
  234. this.offset = offset;
  235. }
  236.  
  237. Result(String value, int offset) {
  238. this(value);
  239. this.offset = offset;
  240. }
  241.  
  242.  
  243. public ResultType getType()
  244. {
  245. return type;
  246. }
  247.  
  248. public int getOffset()
  249. {
  250. return offset;
  251. }
  252.  
  253. public void setOffset(int offset) {
  254. this.offset = offset;
  255. }
  256.  
  257. public int getIntValue() {
  258. return intvalue;
  259. }
  260.  
  261. public double getDblValue() {
  262. return dblvalue;
  263. }
  264.  
  265. public Number getNumValue()
  266. {
  267. if (ResultType.INT.equals(type)) {
  268. return Integer.valueOf(intvalue);
  269. } else if (ResultType.DBL.equals(type)) {
  270. return Double.valueOf(dblvalue);
  271. } else {
  272. return null;
  273. }
  274. }
  275. public String getStrValue()
  276. {
  277. return strvalue;
  278. }
  279.  
  280. public boolean isNumber() {
  281. return ResultType.INT.equals(type) || ResultType.DBL.equals(type);
  282. }
  283.  
  284. public boolean isInt() {
  285. return ResultType.INT.equals(type);
  286. }
  287.  
  288. public boolean isDbl() {
  289. return ResultType.DBL.equals(type);
  290. }
  291.  
  292. public boolean isString() {
  293. return ResultType.STR.equals(type);
  294. }
  295. }
  296.  
  297. final class Excutor
  298. {
  299. private NavigableMap<Integer, List<Token>> program = new TreeMap<Integer, List<Token>>();
  300.  
  301. private Map<String, VarArray<String>> strarrs = new HashMap<String, VarArray<String>>();
  302. private Map<String, VarArray<Number>> numarrs = new HashMap<String, VarArray<Number>>();
  303. private Map<String, String> strvars = new HashMap<String, String>();
  304. private Map<String, Number> numvars = new HashMap<String, Number>();
  305.  
  306. private Integer programcounter = null;
  307. private Deque<Integer> programcounterstack = new ArrayDeque<Integer>();
  308.  
  309. private int arraybase = 0;
  310. private boolean jumpflag = false;
  311. private boolean stopflag = false;
  312. private boolean endflag = false;
  313.  
  314. private Set<String> editorcommandnames = new HashSet<String>();
  315. private Set<String> commandnames = new HashSet<String>();
  316. private Set<String> functionnames = new HashSet<String>();
  317. private Set<String> keywordnames = new HashSet<String>();
  318.  
  319. private Map<String, Integer> opepriority = new HashMap<String, Integer>();
  320.  
  321. private Random rand = new Random();
  322. private double lastrand = 0;
  323.  
  324. private int tabcount = 0;
  325.  
  326. public Excutor() {
  327. String[] edcmd = { "RUN", "LOAD", "SAVE", "LIST", "RENUM", "CONT" };
  328. String[] cmd = { "PRINT", "INPUT", "LET", "REM", "STOP", "END", "GOTO",
  329. "GO", "TO", "GOSUB", "RETURN", "BASE", "DIM", "IF", "THEN", "ELSE",
  330. "FOR", "NEXT", "STEP", "BREAK", "RESTORE", "FILE", "READ", "DATA", "WRITE"};
  331. String[] fnc = { "INT", "STR$", "RND", "CLK", "ABS", "VAL", "SIN", "COS", "TAN",
  332. "SGN", "SQRT", "EXP", "LOG", "LEFT$", "RIGHT$", "MID$"};
  333. String[] key = { "AND", "OR" };
  334. String[] ope = { "OR", "AND", "=", ">=", "<=", "<", ">", "+", "-", "*", "/" };
  335.  
  336.  
  337. for (String s : edcmd) editorcommandnames.add(s);
  338. for (String s : cmd) commandnames.add(s);
  339. for (String s : fnc) functionnames.add(s);
  340. for (String s : key) keywordnames.add(s);
  341.  
  342. for (int i = 0; i < ope.length; i++) {
  343. opepriority.put(ope[i], Integer.valueOf(i));
  344. }
  345. }
  346.  
  347. private boolean checkKeyword(String name) {
  348. return editorcommandnames.contains(name)
  349. || commandnames.contains(name)
  350. || functionnames.contains(name)
  351. || keywordnames.contains(name);
  352. }
  353.  
  354. private void printLine(List<Token> tokens) {
  355. printLine(Integer.valueOf(tokens.get(0).getToken()), tokens);
  356. }
  357.  
  358. private void printLine(Integer linenum, List<Token> tokens)
  359. {
  360. int s = 0;
  361. if (linenum != null) {
  362. System.out.printf("%05d ", linenum.intValue());
  363. s = 1;
  364. }
  365. TokenType before = null, type;
  366. for (int i = s; i < tokens.size(); i++) {
  367. Token token = tokens.get(i);
  368. type = token.getType();
  369. if (TokenType.NAME.equals(before)) {
  370. switch (type) {
  371. case NAME:
  372. case INT:
  373. case DBL:
  374. case SHARP:
  375. case STR:
  376. System.out.print(' ');
  377. break;
  378. default:
  379. break;
  380. }
  381. }
  382. System.out.print(tokens.get(i).getToken());
  383. before = type;
  384. }
  385. System.out.println();
  386. }
  387.  
  388. private Result checksign(Result temp, int sign) throws SyntaxError {
  389. switch (temp.getType()) {
  390. case INT:
  391. if (sign < 0) {
  392. return new Result( - temp.getNumValue().intValue(), temp.getOffset());
  393. }
  394. break;
  395. case DBL:
  396. if (sign < 0) {
  397. return new Result( - temp.getNumValue().doubleValue(), temp.getOffset());
  398. }
  399. break;
  400. case STR:
  401. if (sign == 0) {
  402. break;
  403. }
  404. default:
  405. throw new SyntaxError("invalid sign character");
  406. }
  407. return temp;
  408. }
  409.  
  410. private Result calc2(int temp1, int temp2, String op) throws SyntaxError {
  411. int res = 0;
  412. switch (op) {
  413. case "+": res = temp1 + temp2; break; // TODO OverFlow どした
  414. case "-": res = temp1 - temp2; break;
  415. case "*": res = temp1 * temp2; break;
  416. case "/": if (temp2 == 0) {
  417. throw new ExcuteError("Zero divided");
  418. }
  419. res = temp1 / temp2; break;
  420. case "=": res = temp1 == temp2 ? -1 : 0; break;
  421. case ">": res = temp1 > temp2 ? -1 : 0; break;
  422. case "<": res = temp1 < temp2 ? -1 : 0; break;
  423. case ">=": res = temp1 >= temp2 ? -1 : 0; break;
  424. case "<=": res = temp1 <= temp2 ? -1 : 0; break;
  425. case "AND": res = (temp1 & temp2) != 0 ? -1 : 0; break;
  426. case "OR": res = (temp1 | temp2) != 0 ? -1 : 0; break;
  427. default:
  428. throw new SyntaxError("Invalid operator: " + op);
  429. }
  430. return new Result(res);
  431. }
  432.  
  433. private Result calc2(double temp1, double temp2, String op) throws SyntaxError {
  434. double res = 0;
  435. switch (op) {
  436. case "+": res = temp1 + temp2; break; // TODO OverFlow どした
  437. case "-": res = temp1 - temp2; break;
  438. case "*": res = temp1 * temp2; break;
  439. case "/": if (temp2 == 0) {
  440. throw new ExcuteError("Zero divided");
  441. }
  442. res = temp1 / temp2; break;
  443. case "=": return Result.getBool(temp1 == temp2);
  444. case ">": return Result.getBool(temp1 > temp2);
  445. case "<": return Result.getBool(temp1 < temp2);
  446. case ">=": return Result.getBool(temp1 >= temp2);
  447. case "<=": return Result.getBool(temp1 <= temp2);
  448. case "AND": return Result.getBool(temp1 * temp2 != 0.0);
  449. case "OR": return Result.getBool(temp1 != 0.0 || temp2 != 0.0);
  450. default:
  451. throw new SyntaxError("Invalid operator: " + op);
  452. }
  453. return new Result(res);
  454. }
  455.  
  456. private Result calc2(String temp1, String temp2, String op) throws SyntaxError {
  457. String res;
  458. switch (op) {
  459. case "-":
  460. case "*":
  461. case "/":
  462. case "AND":
  463. case "OR": throw new SyntaxError("Invalid str operetor: " + op);
  464. case "+": return new Result(temp1 + temp2);
  465. case "=": return Result.getBool(temp1.equals(temp2));
  466. case ">": return Result.getBool(temp1.compareTo(temp2) > 0);
  467. case "<": return Result.getBool(temp1.compareTo(temp2) < 0);
  468. case ">=": return Result.getBool(temp1.compareTo(temp2) >= 0);
  469. case "<=": return Result.getBool(temp1.compareTo(temp2) <= 0);
  470. default:
  471. throw new SyntaxError("Invalid operator: " + op);
  472. }
  473. }
  474.  
  475. private Result calc2(Result temp1, Result temp2, String op) throws SyntaxError {
  476. if (temp1.getType().equals(temp2.getType())) {
  477. switch (temp1.getType()) {
  478. case INT:
  479. return calc2(temp1.getIntValue(), temp2.getIntValue(), op);
  480. case DBL:
  481. return calc2(temp1.getDblValue(), temp2.getDblValue(), op);
  482. case STR:
  483. return calc2(temp1.getStrValue(), temp2.getStrValue(), op);
  484. default:
  485. throw new ExcuteError("Invalid type value");
  486. }
  487. } else if (ResultType.INT.equals(temp1.getType())
  488. && ResultType.DBL.equals(temp2.getType())) {
  489. return calc2(temp1.getNumValue().doubleValue(), temp2.getDblValue(), op);
  490. } else if (ResultType.DBL.equals(temp1.getType())
  491. && ResultType.INT.equals(temp2.getType())) {
  492. return calc2(temp1.getDblValue(), temp2.getNumValue().doubleValue(), op);
  493. } else {
  494. throw new ExcuteError("Invalid type value");
  495. }
  496.  
  497. }
  498.  
  499. private boolean calccheck(String op1, String op2) throws SyntaxError {
  500. Integer p1 = opepriority.get(op1);
  501. Integer p2 = opepriority.get(op2);
  502. if (p1 == null || p2 == null) {
  503. throw new SyntaxError("Invalid expression symbol");
  504. }
  505. return p2.compareTo(p1) < 0;
  506. }
  507.  
  508. private Result calc(List<Token> tokens, int index) throws SyntaxError
  509. {
  510. if (index >= tokens.size()) {
  511. throw new SyntaxError(tokens, index);
  512. }
  513.  
  514. Deque<Result> r_stack = new ArrayDeque<Result>();
  515. Deque<String> s_stack = new ArrayDeque<String>();
  516. int sign = 0;
  517. int flag = 0;
  518. Result temp, temp2;
  519.  
  520. for (; index < tokens.size(); index++) {
  521. Token cur = tokens.get(index);
  522. TokenType type = cur.getType();
  523. String token = cur.getToken();
  524.  
  525. if (flag == 0) {
  526. flag = 1;
  527. switch (type) {
  528. case SYMBL:
  529. if (sign != 0) {
  530. throw new SyntaxError(tokens, index);
  531. }
  532. if ("+".equals(token)) {
  533. sign = 1;
  534. } else if ("-".equals(token)) {
  535. sign = -1;
  536. } else {
  537. throw new SyntaxError(tokens, index);
  538. }
  539. flag = 0;
  540. break;
  541. case INT:
  542. r_stack.push(checksign(new Result(Integer.parseInt(token), index), sign));
  543. break;
  544. case DBL:
  545. r_stack.push(checksign(new Result(Double.parseDouble(token), index), sign));
  546. break;
  547. case STR:
  548. r_stack.push(checksign(new Result(token.substring(1, token.length() - 1), index), sign));
  549. break;
  550. case OP_BRKT:
  551. temp = calc(tokens, index + 1);
  552. index = temp.getOffset();
  553. if (TokenType.CL_BRKT.equals(tokens.get(index).getType()) == false) {
  554. throw new SyntaxError(tokens, index);
  555. }
  556. r_stack.push(checksign(temp, sign));
  557. break;
  558. case NAME:
  559. if (functionnames.contains(token)) {
  560. temp = doFunction(tokens, index);
  561. index = temp.getOffset();
  562. r_stack.push(checksign(temp, sign));
  563. } else if (strarrs.containsKey(token)) {
  564. temp = get_strarr(tokens, index);
  565. index = temp.getOffset();
  566. r_stack.push(checksign(temp, sign));
  567. } else if (strvars.containsKey(token)) {
  568. r_stack.push(checksign(new Result(strvars.get(token), index), sign));
  569. } else if (numarrs.containsKey(token)) {
  570. temp = get_numarr(tokens, index);
  571. index = temp.getOffset();
  572. r_stack.push(checksign(temp, sign));
  573. } else if (numvars.containsKey(token)) {
  574. r_stack.push(checksign(new Result(numvars.get(token), index), sign));
  575. } else if (checkKeyword(token)) {
  576. throw new SyntaxError("Invalid name");
  577. } else if (token.lastIndexOf("$") > 0) {
  578. // 未定義 文字列 変数
  579. if (index + 1 < tokens.size() && "(".equals(tokens.get(index + 1).getToken())) {
  580. // 配列
  581. temp = get_strarr(tokens, index);
  582. index = temp.getOffset();
  583. r_stack.push(checksign(temp, sign));
  584. } else {
  585. strvars.put(token, "");
  586. r_stack.push(checksign(new Result("", index), sign));
  587. }
  588. } else {
  589. // 未定義 数値 変数
  590. if (index + 1 < tokens.size() && "(".equals(tokens.get(index + 1).getToken())) {
  591. // 配列
  592. temp = get_numarr(tokens, index);
  593. index = temp.getOffset();
  594. r_stack.push(checksign(temp, sign));
  595. } else {
  596. numvars.put(token, Integer.valueOf(0));
  597. r_stack.push(checksign(new Result(0, index), sign));
  598. }
  599. }
  600. break;
  601. default:
  602. throw new SyntaxError(tokens, index);
  603. }
  604. } else if (flag == 1) {
  605. flag = 0;
  606. sign = 0;
  607. switch (type) {
  608. case NAME:
  609. switch (token) {
  610. case "OR":
  611. case "AND":
  612. temp = r_stack.peek();
  613. if (ResultType.STR.equals(temp.getType())) {
  614. throw new ExcuteError("Invalid expression symbol");
  615. }
  616. break;
  617. default:
  618. throw new SyntaxError(tokens, index);
  619. }
  620. case SYMBL:
  621. switch (token) {
  622. case "-":
  623. case "*":
  624. case "/":
  625. temp = r_stack.peek();
  626. if (ResultType.STR.equals(temp.getType())) {
  627. throw new ExcuteError("Invalid expression symbol");
  628. }
  629. default:
  630. break;
  631. }
  632. while (s_stack.size() > 0 && calccheck(s_stack.peek(), token)) {
  633. if (r_stack.size() < 2) {
  634. throw new ExcuteError("Unknown error");
  635. }
  636. temp2 = r_stack.pop();
  637. temp = r_stack.pop();
  638. temp = calc2(temp, temp2, s_stack.pop());
  639. r_stack.push(temp);
  640. }
  641. s_stack.push(token);
  642. break;
  643. case COLON:
  644. case SEMICOLON:
  645. case COMMA:
  646. case CL_BRKT:
  647. while (s_stack.size() > 0) {
  648. if (r_stack.size() < 2) {
  649. throw new ExcuteError("Unknown error");
  650. }
  651. temp2 = r_stack.pop();
  652. temp = r_stack.pop();
  653. temp = calc2(temp, temp2, s_stack.pop());
  654. r_stack.push(temp);
  655. }
  656. if (r_stack.size() != 1) {
  657. throw new ExcuteError("Unknown error");
  658. }
  659. temp = r_stack.pop();
  660. temp.setOffset(index);
  661. return temp;
  662. default:
  663. throw new SyntaxError(tokens, index);
  664. }
  665. }
  666. }
  667.  
  668.  
  669. if (flag == 0) {
  670. if (r_stack.size() > 0 || s_stack.size() > 0) {
  671. System.out.println("hoge");
  672. throw new SyntaxError(tokens, index);
  673. }
  674. return Result.getEOL(index);
  675. }
  676.  
  677. while (s_stack.size() > 0) {
  678. if (r_stack.size() < 2) {
  679. throw new ExcuteError("Unknown error");
  680. }
  681. temp2 = r_stack.pop();
  682. temp = r_stack.pop();
  683. temp = calc2(temp, temp2, s_stack.pop());
  684. r_stack.push(temp);
  685. }
  686. if (r_stack.size() != 1) {
  687. throw new ExcuteError("Unknown error");
  688. }
  689. temp = r_stack.pop();
  690. temp.setOffset(index);
  691. return temp;
  692. }
  693.  
  694. public Result get_strarr(List<Token> tokens, int index) throws SyntaxError
  695. {
  696. return Result.getEOL(index);
  697. }
  698.  
  699. public Result get_numarr(List<Token> tokens, int index) throws SyntaxError
  700. {
  701. return Result.getEOL(index);
  702. }
  703.  
  704. public Result doFunction(List<Token> tokens, int index) throws SyntaxError
  705. {
  706. if (index + 1 >= tokens.size()) {
  707. throw new SyntaxError(tokens, index);
  708. }
  709. if (TokenType.OP_BRKT.equals(tokens.get(index + 1).getType()) == false) {
  710. throw new SyntaxError(tokens, index);
  711. }
  712. String name = tokens.get(index).getToken();
  713. Result temp;
  714. switch (name) {
  715. case "INT":
  716. temp = calc(tokens, index + 2);
  717. index = temp.getOffset();
  718. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  719. switch (temp.getType()) {
  720. case INT:
  721. return temp;
  722. case DBL:
  723. return new Result(temp.getNumValue().intValue(), index);
  724. default:
  725. break;
  726. }
  727. }
  728. throw new SyntaxError(tokens, index);
  729. case "RND":
  730. temp = calc(tokens, index + 2);
  731. index = temp.getOffset();
  732. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  733. switch (temp.getType()) {
  734. case INT:
  735. case DBL:
  736. int s = temp.getNumValue().intValue();
  737. if (s == 0) {
  738. return new Result(lastrand = rand.nextDouble(), index);
  739. } else if (s > 0) {
  740. rand.setSeed((long)s);
  741. lastrand = rand.nextDouble();
  742. }
  743. return new Result(lastrand, index);
  744. default:
  745. break;
  746. }
  747. }
  748. throw new SyntaxError(tokens, index);
  749. case "CLK":
  750. temp = calc(tokens, index + 2);
  751. index = temp.getOffset();
  752. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  753. switch (temp.getType()) {
  754. case INT:
  755. case DBL:
  756. double t = temp.getNumValue().doubleValue();
  757. t -= Math.floor(t);
  758. t *= 24;
  759. return new Result((int)t, index);
  760. default:
  761. break;
  762. }
  763. }
  764. throw new SyntaxError(tokens, index);
  765. case "ABS":
  766. temp = calc(tokens, index + 2);
  767. index = temp.getOffset();
  768. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  769. switch (temp.getType()) {
  770. case INT:
  771. return new Result(Math.abs(temp.getIntValue()), index);
  772. case DBL:
  773. return new Result(Math.abs(temp.getDblValue()), index);
  774. default:
  775. break;
  776. }
  777. }
  778. throw new SyntaxError(tokens, index);
  779. case "VAL":
  780. temp = calc(tokens, index + 2);
  781. index = temp.getOffset();
  782. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  783. switch (temp.getType()) {
  784. case STR:
  785. Matcher mt;
  786. if ((mt = Pattern.compile("^(\\d*\\.\\d+)").matcher(temp.getStrValue())).lookingAt()) {
  787. return new Result(Double.parseDouble(mt.group(1)), index);
  788. } else if ((mt = Pattern.compile("^(\\d+)").matcher(temp.getStrValue())).lookingAt()) {
  789. return new Result(Integer.parseInt(mt.group(1)), index);
  790. } else {
  791. return new Result(0.0, index);
  792. }
  793. default:
  794. break;
  795. }
  796. }
  797. throw new SyntaxError(tokens, index);
  798. default:
  799. break;
  800. }
  801.  
  802. return Result.getEOL(index);
  803. }
  804.  
  805. public int doEditorCommand(List<Token> tokens) throws SyntaxError
  806. {
  807. if (tokens == null || tokens.isEmpty()) {
  808. return 0;
  809. }
  810.  
  811. Token first = tokens.get(0);
  812. String token = first.getToken();
  813. TokenType type = first.getType();
  814.  
  815. if (TokenType.INT.equals(type)) {
  816. Integer tmpint = Integer.valueOf(token);
  817. if (tmpint.intValue() < 1) {
  818. throw new SyntaxError(token);
  819. }
  820. if (tokens.size() > 1) {
  821. program.put(tmpint, tokens);
  822. } else {
  823. program.remove(tmpint);
  824. }
  825. return 0;
  826. } else if (TokenType.NAME.equals(type) == false) {
  827. throw new ExcuteError(token);
  828. }
  829.  
  830. /* */
  831. printLine(null, tokens); // IDEONE上じゃ入力が見えないので
  832. /* */
  833.  
  834. switch (token) {
  835. case "CONT": // プログラムの再開
  836. // TODO 処理
  837. break;
  838. case "EXIT": // インタプリタの終了
  839. return -1;
  840. case "LIST": // プログラムの表示
  841. do_list(tokens);
  842. break;
  843. case "LOAD": // プログラムのロード
  844. // TODO 処理
  845. break;
  846. case "NEW": // プログラムと変数の全消去
  847. // TODO 処理
  848. break;
  849. case "RENUM": // プログラムの行番号再割り当て
  850. // TODO 処理
  851. break;
  852. case "RUN": // プログラムの実行
  853. do_run(tokens);
  854. break;
  855. case "SAVE": // プログラムの保存
  856. // TODO 処理
  857. break;
  858. default:
  859. excute(tokens, 0);
  860. break;
  861. }
  862. if (stopflag) {
  863. System.out.println("Stop");
  864. stopflag = false;
  865. return 0;
  866. }
  867. System.out.println("Ok");
  868. return 0;
  869. }
  870.  
  871. private void do_list(List<Token> tokens) throws SyntaxError
  872. {
  873. Integer start = null;
  874. Integer end = null;
  875. Token first, second, third;
  876. Map<Integer, List<Token>> list = null;
  877. try {
  878. switch (tokens.size()) {
  879. case 1:
  880. list = program;
  881. break;
  882. case 2:
  883. first = tokens.get(1);
  884. if (TokenType.INT.equals(first.getType()) == false) {
  885. throw new SyntaxError(tokens ,1);
  886. }
  887. end = start = Integer.valueOf(first.getToken());
  888. if (start.intValue() < 1) {
  889. throw new SyntaxError(tokens ,1);
  890. }
  891. list = program.subMap(start, true, end, true);
  892. break;
  893. case 3:
  894. first = tokens.get(1);
  895. second = tokens.get(2);
  896. if ("-".equals(first.getToken())) {
  897. if (TokenType.INT.equals(second.getType()) == false) {
  898. throw new SyntaxError(tokens ,2);
  899. }
  900. end = Integer.valueOf(second.getToken());
  901. if (end.intValue() < 1) {
  902. throw new SyntaxError(tokens ,2);
  903. }
  904. list = program.headMap(end, true);
  905. } else if (TokenType.INT.equals(first.getType())) {
  906. start = Integer.valueOf(first.getToken());
  907. if (start.intValue() < 1) {
  908. throw new SyntaxError(tokens , 1);
  909. }
  910. if ("-".equals(second.getToken()) == false) {
  911. throw new SyntaxError(tokens ,2);
  912. }
  913. list = program.tailMap(start);
  914. } else {
  915. throw new SyntaxError(tokens ,1);
  916. }
  917. break;
  918. case 4:
  919. first = tokens.get(1);
  920. if (TokenType.INT.equals(first.getType()) == false) {
  921. throw new SyntaxError(tokens ,1);
  922. }
  923. start = Integer.valueOf(first.getToken());
  924. if (start.intValue() < 1) {
  925. throw new SyntaxError(tokens ,1);
  926. }
  927. if ("-".equals(tokens.get(2).getToken()) == false) {
  928. throw new SyntaxError(tokens ,2);
  929. }
  930. third = tokens.get(3);
  931. if (TokenType.INT.equals(third.getType()) == false) {
  932. throw new SyntaxError(tokens ,3);
  933. }
  934. end = Integer.valueOf(third.getToken());
  935. if (end.intValue() < 1) {
  936. throw new SyntaxError(tokens ,3);
  937. }
  938. list = program.subMap(start, true, end, true);
  939. break;
  940. default:
  941. throw new SyntaxError(tokens, 0);
  942. }
  943. } catch (SyntaxError er) {
  944. throw er;
  945. } catch (Exception ex) {
  946. throw new ExcuteError(ex);
  947. }
  948.  
  949. if (list == null) {
  950. return;
  951. }
  952.  
  953. for (Integer key: list.keySet()) {
  954. printLine(key, list.get(key));
  955. }
  956.  
  957. }
  958.  
  959. private void do_run(List<Token> tokens) throws SyntaxError
  960. {
  961. switch (tokens.size()) {
  962. case 1:
  963. programcounter = program.ceilingKey(Integer.valueOf(1));
  964. if (programcounter == null) {
  965. throw new SyntaxError("Program is not found");
  966. }
  967. break;
  968. case 2:
  969. Token first = tokens.get(1);
  970. if (TokenType.INT.equals(first.getType()) == false) {
  971. throw new SyntaxError("Illegal Argument");
  972. }
  973. programcounter = Integer.valueOf(first.getToken());
  974. if (programcounter.intValue() < 1) {
  975. throw new SyntaxError("Wrong Line Number");
  976. }
  977. if (program.containsKey(programcounter) == false) {
  978. throw new SyntaxError("Not found Line Number");
  979. }
  980. break;
  981. default:
  982. throw new SyntaxError("Illegal Arguments");
  983. }
  984.  
  985. stopflag = endflag = false;
  986. List<Token> line = null;
  987. try {
  988. while (programcounter != null) {
  989. line = program.get(programcounter);
  990. excute(line, 1);
  991. if (jumpflag == false) {
  992. programcounter = program.higherKey(programcounter);
  993. if (stopflag) {
  994. break;
  995. } else if (endflag) {
  996. break;
  997. }
  998. } else {
  999. jumpflag = false;
  1000. }
  1001. }
  1002. } catch (SyntaxError er) {
  1003. printLine(line);
  1004. throw er;
  1005. }
  1006.  
  1007. }
  1008.  
  1009. private int excute(List<Token> tokens, int index) throws SyntaxError
  1010. {
  1011. if (index < 0 || index >= tokens.size()) {
  1012. return tokens.size();
  1013. }
  1014. Token first = tokens.get(index);
  1015. TokenType type = first.getType();
  1016.  
  1017. while (TokenType.COLON.equals(type)) {
  1018. index++;
  1019. if (index == tokens.size()) {
  1020. return index;
  1021. }
  1022. first = tokens.get(index);
  1023. type = first.getType();
  1024. }
  1025.  
  1026. if (TokenType.NAME.equals(type) == false) {
  1027. throw new SyntaxError(first.toString());
  1028. }
  1029. String cmd = first.getToken();
  1030. int offset = index;
  1031. switch (cmd) {
  1032. case "BASE": // 配列の下限(0/1)の設定
  1033. offset = cmd_base(tokens, index + 1);
  1034. break;
  1035. case "BREAK": // FORループの脱出
  1036. // TODO 処理
  1037. break;
  1038. case "DATA": // データの列挙
  1039. // TODO 処理
  1040. break;
  1041. case "DIM": // 配列変数の宣言
  1042. // TODO 処理
  1043. break;
  1044. case "ELSE": // IF文のELSE節の開始
  1045. // TODO 処理
  1046. break;
  1047. case "END": // プログラムの終了
  1048. endflag = true;
  1049. return tokens.size();
  1050. case "FILE": // ファイルの割り当て
  1051. // TODO 処理
  1052. break;
  1053. case "FOR": // 繰り返し
  1054. // TODO 処理
  1055. break;
  1056. case "GO": // GOTOの分割トークン
  1057. if (index + 2 >= tokens.size()) {
  1058. throw new SyntaxError(tokens, index);
  1059. }
  1060. if ("TO".equals(tokens.get(index + 1).getToken()) == false) {
  1061. throw new SyntaxError(tokens, index);
  1062. }
  1063. offset = cmd_goto(tokens, index + 2);
  1064. break;
  1065. case "GOTO": // ジャンプ
  1066. offset = cmd_goto(tokens, index + 1);
  1067. break;
  1068. case "GOSUB": // サブルーチンジャンプ
  1069. offset = cmd_gosub(tokens, index + 1);
  1070. break;
  1071. case "IF": // 条件節
  1072. // TODO 処理
  1073. break;
  1074. case "INPUT": // キーボードからの値の入力
  1075. // TODO 処理
  1076. break;
  1077. case "LET": // 変数への代入
  1078. offset = cmd_let(tokens, index + 1);
  1079. break;
  1080. case "NEXT": // FOR文の末端
  1081. // TODO 処理
  1082. break;
  1083. case "PRINT": // 画面へ値を出力
  1084. offset = cmd_print(tokens, index + 1);
  1085. break;
  1086. case "REM": // コメント行
  1087. offset = tokens.size();
  1088. break;
  1089. case "RESTORE": // データ・ファイルの読み込み位置のリセット
  1090. // TODO 処理
  1091. break;
  1092. case "RETURN": // サブルーチンからの脱出
  1093. offset = cmd_return(tokens, index);
  1094. break;
  1095. case "STOP": // プログラムの中断
  1096. stopflag = true;
  1097. return tokens.size();
  1098. default:
  1099. offset = cmd_let(tokens, index);
  1100. break;
  1101. }
  1102. return offset;
  1103. }
  1104.  
  1105. @Override
  1106. public String toString()
  1107. {
  1108. return program.toString().replaceAll("(\\d+=\\[\\[)", "\n$1");
  1109. }
  1110.  
  1111. private int cmd_goto(List<Token> tokens, int index) throws SyntaxError
  1112. {
  1113. if (index >= tokens.size()) {
  1114. throw new SyntaxError(tokens, index);
  1115. }
  1116. if (index + 1 < tokens.size()) {
  1117. if (TokenType.COLON.equals(tokens.get(index + 1).getType()) == false) {
  1118. throw new SyntaxError(tokens, index + 1);
  1119. }
  1120. }
  1121. Token first = tokens.get(index);
  1122. if (TokenType.INT.equals(first.getType()) == false) {
  1123. throw new SyntaxError(tokens, index);
  1124. }
  1125. Integer next = Integer.valueOf(first.getToken());
  1126. if (program.containsKey(next) == false) {
  1127. throw new SyntaxError(tokens, index);
  1128. }
  1129. programcounter = next;
  1130. jumpflag = true;
  1131. return tokens.size();
  1132. }
  1133.  
  1134. private int cmd_gosub(List<Token> tokens, int index) throws SyntaxError
  1135. {
  1136. if (index >= tokens.size()) {
  1137. throw new SyntaxError(tokens, index);
  1138. }
  1139. if (index + 1 < tokens.size()) {
  1140. if (TokenType.COLON.equals(tokens.get(index + 1).getType()) == false) {
  1141. throw new SyntaxError(tokens, index + 1);
  1142. }
  1143. }
  1144. Token first = tokens.get(index);
  1145. if (TokenType.INT.equals(first.getType()) == false) {
  1146. throw new SyntaxError(tokens, index);
  1147. }
  1148. Integer next = Integer.valueOf(first.getToken());
  1149. if (program.containsKey(next) == false) {
  1150. throw new SyntaxError(tokens, index);
  1151. }
  1152. try {
  1153. programcounterstack.push(programcounter);
  1154. programcounter = next;
  1155. jumpflag = true;
  1156. return tokens.size();
  1157. } catch (Exception ex) {
  1158. throw new ExcuteError(ex);
  1159. }
  1160. }
  1161.  
  1162. private int cmd_return(List<Token> tokens, int index) throws SyntaxError
  1163. {
  1164. if (index < tokens.size()) {
  1165. if (TokenType.COLON.equals(tokens.get(index).getType()) == false) {
  1166. throw new SyntaxError(tokens, index);
  1167. }
  1168. }
  1169. try {
  1170. Integer back = programcounterstack.pop();
  1171. programcounter = program.higherKey(back);
  1172. jumpflag = true;
  1173. return tokens.size();
  1174. } catch (Exception ex) {
  1175. throw new ExcuteError(ex);
  1176. }
  1177. }
  1178.  
  1179.  
  1180. private int cmd_base(List<Token> tokens, int index) throws SyntaxError
  1181. {
  1182. try {
  1183. Token first = tokens.get(index);
  1184. if (TokenType.INT.equals(first.getType()) == false) {
  1185. throw new SyntaxError(tokens, index);
  1186. }
  1187. int tmpint = Integer.parseInt(first.getToken());
  1188. if (tmpint != 0 && tmpint != 1) {
  1189. throw new SyntaxError(tokens, index + 1);
  1190. }
  1191. arraybase = tmpint;
  1192. return excute(tokens, index + 1);
  1193. } catch (SyntaxError er) {
  1194. throw er;
  1195. } catch (Exception ex) {
  1196. throw new ExcuteError(ex);
  1197. }
  1198. }
  1199.  
  1200. private int cmd_print(List<Token> tokens, int index) throws SyntaxError
  1201. {
  1202. if (index == tokens.size()) {
  1203. tabcount = 0;
  1204. System.out.println();
  1205. return tokens.size();
  1206. } else if (index > tokens.size()) {
  1207. throw new ExcuteError("Unknown error");
  1208. }
  1209. StringBuilder output = new StringBuilder();
  1210. boolean nl = true;
  1211. for (; index < tokens.size(); index++) {
  1212. Token cur = tokens.get(index);
  1213. switch (cur.getType()) {
  1214. case COLON:
  1215. if (nl) {
  1216. tabcount = 0;
  1217. System.out.println(output);
  1218. } else {
  1219. tabcount += output.length();
  1220. System.out.print(output);
  1221. }
  1222. return excute(tokens, index + 1);
  1223. case COMMA:
  1224. output.append('\t');
  1225. nl = false;
  1226. break;
  1227. case SEMICOLON:
  1228. nl = false;
  1229. break;
  1230. case INT:
  1231. case DBL:
  1232. case STR:
  1233. case NAME:
  1234. Result temp = calc(tokens, index);
  1235. index = temp.getOffset() - 1;
  1236. switch (temp.getType()) {
  1237. case INT: output.append(temp.getIntValue()); break;
  1238. case DBL: output.append(temp.getDblValue()); break;
  1239. case STR: output.append(temp.getStrValue()); break;
  1240. default:
  1241. throw new ExcuteError("Unknown error");
  1242. }
  1243. nl = true;
  1244. break;
  1245. }
  1246. }
  1247. if (nl) {
  1248. tabcount = 0;
  1249. System.out.println(output);
  1250. } else {
  1251. tabcount += output.length();
  1252. System.out.print(output);
  1253. }
  1254. return excute(tokens, index);
  1255. }
  1256.  
  1257. private int cmd_let(List<Token> tokens, int index) throws SyntaxError
  1258. {
  1259. try {
  1260. if (index + 2 >= tokens.size()) {
  1261. throw new SyntaxError(tokens, index);
  1262. }
  1263. Token first = tokens.get(index);
  1264. String name = first.getToken();
  1265. if (checkKeyword(name)) { // 予約語チェック
  1266. throw new SyntaxError("Wrong variable name: " + name);
  1267. }
  1268. index++;
  1269. Result temp;
  1270. if (name.lastIndexOf("$") > 0) {
  1271. if (strarrs.containsKey(name)) {
  1272. if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
  1273. throw new SyntaxError(tokens, index);
  1274. }
  1275. // TODO 配列の添え字の読み取りとか
  1276.  
  1277. } else {
  1278. if ("=".equals(tokens.get(index).getToken()) == false) {
  1279. throw new SyntaxError(tokens, index);
  1280. }
  1281. index++;
  1282. temp = calc(tokens, index);
  1283. if (ResultType.STR.equals(temp.getType()) == false) {
  1284. throw new ExcuteError("Invalid type value");
  1285. }
  1286. index = temp.getOffset();
  1287. strvars.put(name, temp.getStrValue());
  1288. }
  1289. } else {
  1290. if (numarrs.containsKey(name)) {
  1291. if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
  1292. throw new SyntaxError(tokens, index);
  1293. }
  1294. // TODO 配列の添え字の読み取りとか
  1295.  
  1296. } else if (numvars.containsKey(name)) {
  1297. if ("=".equals(tokens.get(index).getToken()) == false) {
  1298. throw new SyntaxError(tokens ,index);
  1299. }
  1300. index++;
  1301. temp = calc(tokens, index);
  1302. index = temp.getOffset();
  1303. Number num = numvars.get(name);
  1304. switch (temp.getType()) {
  1305. case INT:
  1306. if (Integer.class.equals(num.getClass())) {
  1307. numvars.put(name, temp.getNumValue());
  1308. } else if (Double.class.equals(num.getClass())) {
  1309. numvars.put(name, Double.valueOf(temp.getNumValue().doubleValue()));
  1310. } else {
  1311. throw new ExcuteError("Invalid type value");
  1312. }
  1313. break;
  1314. case DBL:
  1315. if (Integer.class.equals(num.getClass())) {
  1316. numvars.put(name, Integer.valueOf(temp.getNumValue().intValue()));
  1317. } else if (Double.class.equals(num.getClass())) {
  1318. numvars.put(name, temp.getNumValue());
  1319. } else {
  1320. throw new ExcuteError("Invalid type value");
  1321. }
  1322. break;
  1323. default:
  1324. throw new ExcuteError("Invalid type value");
  1325. }
  1326. } else {
  1327. if ("=".equals(tokens.get(index).getToken()) == false) {
  1328. throw new SyntaxError(tokens, index);
  1329. }
  1330. index++;
  1331. temp = calc(tokens, index);
  1332. index = temp.getOffset();
  1333. switch (temp.getType()) {
  1334. case INT:
  1335. case DBL:
  1336. numvars.put(name, temp.getNumValue());
  1337. break;
  1338. default:
  1339. throw new ExcuteError("Invalid type value");
  1340. }
  1341. }
  1342. }
  1343. return excute(tokens, index + 1);
  1344. } catch (SyntaxError er) {
  1345. throw er;
  1346. } catch (Exception ex) {
  1347. // ex.printStackTrace();
  1348. throw new ExcuteError(tokens.toString());
  1349. }
  1350.  
  1351. }
  1352.  
  1353. }
Success #stdin #stdout 0.09s 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"
let x=10+1
print x
let y=1.0
print y
y=y*3
print x,y
s$="hoge"
print s$
s$=s$+"unko"
print s$
print rnd(123)
print int(rnd(0)*24), int(rnd(0)*24), int(rnd(0)*24)
stdout
*** BASIC Interpreter ***
Ok

LET X=10+1
Ok
PRINT X
11
Ok
LET Y=1.0
Ok
PRINT Y
1.0
Ok
Y=Y*3
Ok
PRINT X,Y
11	3.0
Ok
S$="hoge"
Ok
PRINT S$
hoge
Ok
S$=S$+"unko"
Ok
PRINT S$
hogeunko
Ok
PRINT RND(123)
0.7231742029971469
Ok
PRINT INT(RND(0)*24),INT(RND(0)*24),INT(RND(0)*24)
23	6	14
Ok