fork(1) download
  1. /* BASIC Interpreter
  2.  * for ttps://www.shroudoftheavatar.com/?p=39149#more-39149
  3.  * ttps://d2sx9mrt4zumaq.cloudfront.net/wp-content/uploads/2014/04/DND1_Complete.pdf
  4.  *
  5.  * Version 0.4a (未完成公開)
  6.  *
  7.  * 実装履歴
  8.  * 2014-04-30 v0.1a (作業時間:約6時間)
  9.  * ・コマンドライン入力文のトークン分解
  10.  * ・プログラムリストの入力
  11.  * ・プログラムリストの出力(LIST)
  12.  * ・プログラムリストの開始(RUN)
  13.  * ・ジャンプ系の仮実装(GOTO,GOSUB,RETURN)
  14.  * ・配列添字の最小値設定の仮実装(BASE)
  15.  * 2014-05-01 v0.2a (作業時間:約0.5時間)
  16.  * ・プログラムリストの出力の修正(LIST)
  17.  * 2014-05-04 v0.3a (作業時間:約8時間)
  18.  * ・式の計算(演算子等,但し配列変数を除く)
  19.  * ・値の出力(PRINT)
  20.  * ・変数への代入(LET,但し配列変数を除く)
  21.  * ・関数(INT,ABS,RND,CLK,(VAL))
  22.  * 2014-05-05 v0.4a (作業時間:約5時間)
  23.  * ・配列変数の操作(DIM,LET,式の計算)
  24.  */
  25. import java.util.*;
  26. import java.lang.*;
  27. import java.io.*;
  28. import java.util.regex.*;
  29.  
  30. class Basic
  31. {
  32. static final int major = 0;
  33. static final int minor = 4;
  34. static final char release = 'a';
  35.  
  36. public static void main (String[] args) throws java.lang.Exception
  37. {
  38. System.out.printf("BASIC Interpreter - Version %d.%d%c", major, minor, release);
  39. System.out.println();
  40. System.out.println("Your code goes here!");
  41. System.out.println();
  42. try {
  43. Excutor excutor = new Excutor();
  44. String line;
  45. while ((line = in.readLine()) != null) {
  46. try {
  47. List<Token> tokens = Tokenizer.tokenize(line);
  48. if (excutor.doEditorCommand(tokens) < 0) {
  49. break;
  50. }
  51. } catch (SyntaxError er) {
  52. System.out.println(er);
  53. }
  54. }
  55. // System.out.println(excutor);
  56. } catch (Exception ex) {
  57. System.out.println(ex);
  58. }
  59.  
  60. }
  61. }
  62.  
  63. final class Debug
  64. {
  65. public static boolean isIDEONE() { return true; }
  66. }
  67.  
  68. enum TokenType
  69. {
  70. INT, DBL, STR, NAME, SYMBL, SHARP, SEMICOLON,
  71. OP_BRKT, CL_BRKT, COMMA, COLON, UNKNOWN
  72. }
  73.  
  74. final class Token
  75. {
  76. final TokenType type;
  77. final String token;
  78.  
  79. public Token(TokenType type, String token)
  80. {
  81. this.type = type;
  82. this.token = token;
  83. }
  84.  
  85. public TokenType getType() { return type; }
  86. public String getToken() { return token; }
  87.  
  88. @Override
  89. public String toString()
  90. {
  91. return "[" + type + " : " + token + "]";
  92. }
  93.  
  94. public boolean isInt() { return TokenType.INT.equals(type); }
  95. public boolean isStr() { return TokenType.STR.equals(type); }
  96. public boolean isDbl() { return TokenType.DBL.equals(type); }
  97. public boolean isName() { return TokenType.NAME.equals(type); }
  98. public boolean isSymbl() { return TokenType.SYMBL.equals(type); }
  99. public boolean isOpBrkt() { return TokenType.OP_BRKT.equals(type); }
  100. public boolean isClBrkt() { return TokenType.CL_BRKT.equals(type); }
  101. public boolean isColon() { return TokenType.COLON.equals(type); }
  102. public boolean isSemiColon() { return TokenType.SEMICOLON.equals(type); }
  103. public boolean isComma() { return TokenType.COMMA.equals(type); }
  104. public boolean isSharp() { return TokenType.SHARP.equals(type); }
  105. }
  106.  
  107. class SyntaxError extends java.lang.Exception
  108. {
  109. public SyntaxError(String msg) { super(msg); }
  110. public SyntaxError(Throwable ex) { super(ex); }
  111. public SyntaxError(List<Token> tokens, int index)
  112. {
  113. super("token index(" + index + "): " + tokens.toString());
  114. }
  115. }
  116.  
  117. final class TokenError extends SyntaxError
  118. {
  119. public TokenError(String line) { super(line); }
  120. }
  121.  
  122. final class Tokenizer
  123. {
  124. private static Pattern p_space = Pattern.compile("^\\s+");
  125. private static Pattern p_int = Pattern.compile("^\\d+");
  126. private static Pattern p_dbl = Pattern.compile("^\\d*\\.\\d+");
  127. private static Pattern p_str = Pattern.compile("^\"(\"\"|[^\"])*\"");
  128. private static Pattern p_name = Pattern.compile("^[A-Za-z][A-Za-z0-9]*\\$?");
  129. private static Pattern p_symbl = Pattern.compile("^(>=|<=|<>|[=<>+\\*/-])");
  130.  
  131. public static List<Token> tokenize(String line) throws TokenError
  132. {
  133. List<Token> list = new ArrayList<Token>();
  134. Matcher m = null;
  135. TokenType type = null;
  136. String token = null;
  137. int offset = 0;
  138.  
  139. while (line.length() > 0) {
  140. if ((m = p_space.matcher(line)).lookingAt()) {
  141. line = line.substring(m.end());
  142. continue;
  143. } else if ((m = p_dbl.matcher(line)).lookingAt()) {
  144. type = TokenType.DBL;
  145. } else if ((m = p_int.matcher(line)).lookingAt()) {
  146. type = TokenType.INT;
  147. } else if ((m = p_str.matcher(line)).lookingAt()) {
  148. type = TokenType.STR;
  149. } else if ((m = p_name.matcher(line)).lookingAt()) {
  150. type = TokenType.NAME;
  151. } else if ((m = p_symbl.matcher(line)).lookingAt()) {
  152. type = TokenType.SYMBL;
  153. } else {
  154. m = null;
  155. offset = 1;
  156. if (line.startsWith(token = "(")) {
  157. type = TokenType.OP_BRKT;
  158. } else if (line.startsWith(token = ")")) {
  159. type = TokenType.CL_BRKT;
  160. } else if (line.startsWith(token = ":")) {
  161. type = TokenType.COLON;
  162. } else if (line.startsWith(token = ",")) {
  163. type = TokenType.COMMA;
  164. } else if (line.startsWith(token = "#")) {
  165. type = TokenType.SHARP;
  166. } else if (line.startsWith(token = ";")) {
  167. type = TokenType.SEMICOLON;
  168. } else {
  169. throw new TokenError(line);
  170. }
  171. }
  172. if (m != null) {
  173. token = m.group();
  174. if (TokenType.NAME.equals(type)) {
  175. token = token.toUpperCase();
  176. }
  177. offset = m.end();
  178. }
  179. list.add(new Token(type, token));
  180. line = line.substring(offset);
  181. }
  182. return list;
  183. }
  184. }
  185.  
  186. final class ExcuteError extends SyntaxError
  187. {
  188. public ExcuteError(Throwable ex) { super(ex); }
  189. public ExcuteError(String msg) { super(msg); }
  190. }
  191.  
  192. enum VarArrayType
  193. {
  194. INT, DBL, STR, UNKNOWN
  195. }
  196.  
  197. class VarArray
  198. {
  199. int[] intarr = null;
  200. double[] dblarr = null;
  201. String[] strarr = null;
  202. VarArrayType type = VarArrayType.UNKNOWN;
  203. List<Integer> dim;
  204. int maxdim = 1;
  205.  
  206. VarArray(List<Integer> dim) throws SyntaxError
  207. {
  208. if (dim == null || dim.size() < 1) {
  209. throw new NullPointerException();
  210. }
  211. this.dim = new ArrayList<Integer>(dim);
  212. for (Integer i : dim) {
  213. maxdim *= 1 + i.intValue();
  214. }
  215. if (maxdim < 1) {
  216. throw new SyntaxError("Invalid define array dimention");
  217. }
  218. }
  219.  
  220. public VarArrayType getType()
  221. {
  222. return type;
  223. }
  224.  
  225. public void setType(VarArrayType type) throws SyntaxError
  226. {
  227. if (VarArrayType.UNKNOWN.equals(this.type) == false) {
  228. throw new SyntaxError("already exist array");
  229. }
  230. this.type = type;
  231. switch (type) {
  232. case INT:
  233. intarr = new int[maxdim + 1];
  234. break;
  235. case DBL:
  236. dblarr = new double[maxdim + 1];
  237. break;
  238. case STR:
  239. strarr = new String[maxdim + 1];
  240. break;
  241. default:
  242. throw new SyntaxError("Invalid array type");
  243. }
  244. }
  245.  
  246. private int getIndex(List<Integer> indexes, int base) throws SyntaxError
  247. {
  248. if (indexes == null || indexes.size() != dim.size()) {
  249. throw new SyntaxError("Invalid array indexes " + indexes);
  250. }
  251. int index = 0;
  252. int tmp = 1;
  253. for (int i = 0; i < dim.size(); i++) {
  254. int p = indexes.get(i).intValue();
  255. int max = dim.get(i).intValue();
  256. if (p < base || p > max) {
  257. throw new SyntaxError("array index out of bounds");
  258. }
  259. index += p * tmp;
  260. tmp *= max;
  261. }
  262. return index;
  263. }
  264.  
  265. public void setInt(List<Integer> indexes, int base, int value) throws SyntaxError
  266. {
  267. if (VarArrayType.INT.equals(type) == false) {
  268. throw new SyntaxError("");
  269. }
  270. intarr[getIndex(indexes, base)] = value;
  271. }
  272.  
  273. public void setDbl(List<Integer> indexes, int base, double value) throws SyntaxError {
  274. if (VarArrayType.DBL.equals(type) == false) {
  275. throw new SyntaxError("");
  276. }
  277. dblarr[getIndex(indexes, base)] = value;
  278. }
  279.  
  280. public void setStr(List<Integer> indexes, int base, String value) throws SyntaxError
  281. {
  282. if (VarArrayType.STR.equals(type) == false) {
  283. throw new SyntaxError("");
  284. }
  285. strarr[getIndex(indexes, base)] = value;
  286. }
  287.  
  288. public int getInt(List<Integer> indexes, int base) throws SyntaxError
  289. {
  290. if (VarArrayType.INT.equals(type) == false) {
  291. throw new SyntaxError("");
  292. }
  293. return intarr[getIndex(indexes, base)];
  294. }
  295.  
  296. public double getDbl(List<Integer> indexes, int base) throws SyntaxError
  297. {
  298. if (VarArrayType.DBL.equals(type) == false) {
  299. throw new SyntaxError("");
  300. }
  301. return dblarr[getIndex(indexes, base)];
  302. }
  303.  
  304. public String getStr(List<Integer> indexes, int base) throws SyntaxError
  305. {
  306. if (VarArrayType.STR.equals(type) == false) {
  307. throw new SyntaxError("");
  308. }
  309. String tmp = strarr[getIndex(indexes, base)];
  310. return tmp == null ? "" : tmp;
  311. }
  312.  
  313. }
  314.  
  315. enum ResultType
  316. {
  317. INT, DBL, STR, EOL, UNKNOWN
  318. }
  319.  
  320. class Result
  321. {
  322. public static final Result getTrue()
  323. {
  324. return new Result((int)-1);
  325. }
  326. public static final Result getFalse()
  327. {
  328. return new Result((int)0);
  329. }
  330. public static final Result getBool(boolean bool)
  331. {
  332. return bool ? getTrue() : getFalse();
  333. }
  334.  
  335. private int offset;
  336. private int intvalue = 0;
  337. private double dblvalue = 0;
  338. private String strvalue = null;
  339. private ResultType type;
  340.  
  341. Result()
  342. {
  343. type = ResultType.EOL;
  344. }
  345.  
  346. static Result getEOL(int offset)
  347. {
  348. Result temp = new Result();
  349. temp.offset = offset;
  350. return temp;
  351. }
  352.  
  353. Result(int value)
  354. {
  355. intvalue = value;
  356. type = ResultType.INT;
  357. }
  358.  
  359.  
  360. Result(double value)
  361. {
  362. dblvalue = value;
  363. type = ResultType.DBL;
  364. }
  365.  
  366.  
  367. Result(Number value)
  368. {
  369. if (Integer.class.equals(value.getClass())) {
  370. intvalue = value.intValue();
  371. type = ResultType.INT;
  372. } else if (Double.class.equals(value.getClass())) {
  373. dblvalue = value.doubleValue();
  374. type = ResultType.DBL;
  375. } else {
  376. type = ResultType.UNKNOWN;
  377. }
  378. }
  379.  
  380. Result(String value)
  381. {
  382. strvalue = value;
  383. type = ResultType.STR;
  384. }
  385.  
  386. Result(int value, int offset)
  387. {
  388. this(value);
  389. this.offset = offset;
  390. }
  391.  
  392. Result(double value, int offset)
  393. {
  394. this(value);
  395. this.offset = offset;
  396. }
  397.  
  398. Result(Number value, int offset)
  399. {
  400. this(value);
  401. this.offset = offset;
  402. }
  403.  
  404. Result(String value, int offset)
  405. {
  406. this(value);
  407. this.offset = offset;
  408. }
  409.  
  410.  
  411. public ResultType getType()
  412. {
  413. return type;
  414. }
  415.  
  416. public int getOffset()
  417. {
  418. return offset;
  419. }
  420.  
  421. public void setOffset(int offset)
  422. {
  423. this.offset = offset;
  424. }
  425.  
  426. public int getIntValue()
  427. {
  428. return intvalue;
  429. }
  430.  
  431. public double getDblValue()
  432. {
  433. return dblvalue;
  434. }
  435.  
  436. public Number getNumValue()
  437. {
  438. if (ResultType.INT.equals(type)) {
  439. return Integer.valueOf(intvalue);
  440. } else if (ResultType.DBL.equals(type)) {
  441. return Double.valueOf(dblvalue);
  442. } else {
  443. return null;
  444. }
  445. }
  446. public String getStrValue()
  447. {
  448. return strvalue;
  449. }
  450.  
  451. public boolean isNumber()
  452. {
  453. return ResultType.INT.equals(type) || ResultType.DBL.equals(type);
  454. }
  455.  
  456. public boolean isInt()
  457. {
  458. return ResultType.INT.equals(type);
  459. }
  460.  
  461. public boolean isDbl()
  462. {
  463. return ResultType.DBL.equals(type);
  464. }
  465.  
  466. public boolean isString()
  467. {
  468. return ResultType.STR.equals(type);
  469. }
  470. }
  471.  
  472. final class Excutor
  473. {
  474. private NavigableMap<Integer, List<Token>> program = new TreeMap<Integer, List<Token>>();
  475.  
  476. private Map<String, VarArray> strarrs = new HashMap<String, VarArray>();
  477. private Map<String, VarArray> numarrs = new HashMap<String, VarArray>();
  478. private Map<String, String> strvars = new HashMap<String, String>();
  479. private Map<String, Number> numvars = new HashMap<String, Number>();
  480.  
  481. private Integer programcounter = null;
  482. private Deque<Integer> programcounterstack = new ArrayDeque<Integer>();
  483.  
  484. private int arraybase = 0;
  485. private boolean jumpflag = false;
  486. private boolean stopflag = false;
  487. private boolean endflag = false;
  488.  
  489. private Set<String> editorcommandnames = new HashSet<String>();
  490. private Set<String> commandnames = new HashSet<String>();
  491. private Set<String> functionnames = new HashSet<String>();
  492. private Set<String> keywordnames = new HashSet<String>();
  493.  
  494. private Map<String, Integer> opepriority = new HashMap<String, Integer>();
  495.  
  496. private Random rand = new Random();
  497. private double lastrand = 0;
  498.  
  499. private int tabcount = 0;
  500.  
  501. public Excutor()
  502. {
  503. String[] edcmd = { "RUN", "LOAD", "SAVE", "LIST", "RENUM", "CONT", "NEW" };
  504. String[] cmd = { "PRINT", "INPUT", "LET", "REM", "STOP", "END", "GOTO",
  505. "GO", "TO", "GOSUB", "RETURN", "BASE", "DIM", "IF", "THEN", "ELSE", "ERASE",
  506. "FOR", "NEXT", "STEP", "BREAK", "RESTORE", "FILE", "READ", "DATA", "WRITE"};
  507. String[] fnc = { "INT", "STR$", "RND", "CLK", "ABS", "VAL", "SIN", "COS", "TAN",
  508. "SGN", "SQRT", "EXP", "LOG", "LEFT$", "RIGHT$", "MID$", "LEN"};
  509. String[] key = { "AND", "OR" };
  510. String[] ope = { "OR", "AND", "=", ">=", "<=", "<", ">", "+", "-", "*", "/" };
  511.  
  512.  
  513. for (String s : edcmd) editorcommandnames.add(s);
  514. for (String s : cmd) commandnames.add(s);
  515. for (String s : fnc) functionnames.add(s);
  516. for (String s : key) keywordnames.add(s);
  517.  
  518. for (int i = 0; i < ope.length; i++) {
  519. opepriority.put(ope[i], Integer.valueOf(i));
  520. }
  521. }
  522.  
  523. @Override
  524. public String toString()
  525. {
  526. return program.toString().replaceAll("(\\d+=\\[\\[)", "\n$1");
  527. }
  528.  
  529. private boolean checkKeyword(String name)
  530. {
  531. return editorcommandnames.contains(name)
  532. || commandnames.contains(name)
  533. || functionnames.contains(name)
  534. || keywordnames.contains(name);
  535. }
  536.  
  537. private void printLine(List<Token> tokens)
  538. {
  539. printLine(Integer.valueOf(tokens.get(0).getToken()), tokens);
  540. }
  541.  
  542. private void printLine(Integer linenum, List<Token> tokens)
  543. {
  544. int s = 0;
  545. if (linenum != null) {
  546. System.out.printf("%05d ", linenum.intValue());
  547. s = 1;
  548. }
  549. TokenType before = null, type;
  550. for (int i = s; i < tokens.size(); i++) {
  551. Token token = tokens.get(i);
  552. type = token.getType();
  553. if (TokenType.NAME.equals(before)) {
  554. switch (type) {
  555. case NAME:
  556. case INT:
  557. case DBL:
  558. case SHARP:
  559. case STR:
  560. System.out.print(' ');
  561. break;
  562. default:
  563. break;
  564. }
  565. }
  566. System.out.print(tokens.get(i).getToken());
  567. before = type;
  568. }
  569. System.out.println();
  570. }
  571.  
  572. private Result checksign(Result temp, int sign) throws SyntaxError
  573. {
  574. switch (temp.getType()) {
  575. case INT:
  576. if (sign < 0) {
  577. return new Result( - temp.getNumValue().intValue(), temp.getOffset());
  578. }
  579. break;
  580. case DBL:
  581. if (sign < 0) {
  582. return new Result( - temp.getNumValue().doubleValue(), temp.getOffset());
  583. }
  584. break;
  585. case STR:
  586. if (sign == 0) {
  587. break;
  588. }
  589. default:
  590. throw new SyntaxError("invalid sign character");
  591. }
  592. return temp;
  593. }
  594.  
  595. private Result calc2(int temp1, int temp2, String op) throws SyntaxError
  596. {
  597. int res = 0;
  598. switch (op) {
  599. case "+": res = temp1 + temp2; break; // TODO OverFlow どした
  600. case "-": res = temp1 - temp2; break;
  601. case "*": res = temp1 * temp2; break;
  602. case "/": if (temp2 == 0) {
  603. throw new ExcuteError("Zero divided");
  604. }
  605. res = temp1 / temp2; break;
  606. case "=": res = temp1 == temp2 ? -1 : 0; break;
  607. case ">": res = temp1 > temp2 ? -1 : 0; break;
  608. case "<": res = temp1 < temp2 ? -1 : 0; break;
  609. case ">=": res = temp1 >= temp2 ? -1 : 0; break;
  610. case "<=": res = temp1 <= temp2 ? -1 : 0; break;
  611. case "AND": res = (temp1 & temp2) != 0 ? -1 : 0; break;
  612. case "OR": res = (temp1 | temp2) != 0 ? -1 : 0; break;
  613. default:
  614. throw new SyntaxError("Invalid operator: " + op);
  615. }
  616. return new Result(res);
  617. }
  618.  
  619. private Result calc2(double temp1, double temp2, String op) throws SyntaxError
  620. {
  621. double res = 0;
  622. switch (op) {
  623. case "+": res = temp1 + temp2; break; // TODO OverFlow どした
  624. case "-": res = temp1 - temp2; break;
  625. case "*": res = temp1 * temp2; break;
  626. case "/": if (temp2 == 0) {
  627. throw new ExcuteError("Zero divided");
  628. }
  629. res = temp1 / temp2; break;
  630. case "=": return Result.getBool(temp1 == temp2);
  631. case ">": return Result.getBool(temp1 > temp2);
  632. case "<": return Result.getBool(temp1 < temp2);
  633. case ">=": return Result.getBool(temp1 >= temp2);
  634. case "<=": return Result.getBool(temp1 <= temp2);
  635. case "AND": return Result.getBool(temp1 * temp2 != 0.0);
  636. case "OR": return Result.getBool(temp1 != 0.0 || temp2 != 0.0);
  637. default:
  638. throw new SyntaxError("Invalid operator: " + op);
  639. }
  640. return new Result(res);
  641. }
  642.  
  643. private Result calc2(String temp1, String temp2, String op) throws SyntaxError
  644. {
  645. String res;
  646. switch (op) {
  647. case "-":
  648. case "*":
  649. case "/":
  650. case "AND":
  651. case "OR": throw new SyntaxError("Invalid str operetor: " + op);
  652. case "+": return new Result(temp1 + temp2);
  653. case "=": return Result.getBool(temp1.equals(temp2));
  654. case ">": return Result.getBool(temp1.compareTo(temp2) > 0);
  655. case "<": return Result.getBool(temp1.compareTo(temp2) < 0);
  656. case ">=": return Result.getBool(temp1.compareTo(temp2) >= 0);
  657. case "<=": return Result.getBool(temp1.compareTo(temp2) <= 0);
  658. default:
  659. throw new SyntaxError("Invalid operator: " + op);
  660. }
  661. }
  662.  
  663. private Result calc2(Result temp1, Result temp2, String op) throws SyntaxError
  664. {
  665. if (temp1.getType().equals(temp2.getType())) {
  666. switch (temp1.getType()) {
  667. case INT:
  668. return calc2(temp1.getIntValue(), temp2.getIntValue(), op);
  669. case DBL:
  670. return calc2(temp1.getDblValue(), temp2.getDblValue(), op);
  671. case STR:
  672. return calc2(temp1.getStrValue(), temp2.getStrValue(), op);
  673. default:
  674. throw new ExcuteError("Invalid type value");
  675. }
  676. } else if (ResultType.INT.equals(temp1.getType())
  677. && ResultType.DBL.equals(temp2.getType())) {
  678. return calc2(temp1.getNumValue().doubleValue(), temp2.getDblValue(), op);
  679. } else if (ResultType.DBL.equals(temp1.getType())
  680. && ResultType.INT.equals(temp2.getType())) {
  681. return calc2(temp1.getDblValue(), temp2.getNumValue().doubleValue(), op);
  682. } else {
  683. throw new ExcuteError("Invalid type value");
  684. }
  685.  
  686. }
  687.  
  688. private boolean calccheck(String op1, String op2) throws SyntaxError
  689. {
  690. Integer p1 = opepriority.get(op1);
  691. Integer p2 = opepriority.get(op2);
  692. if (p1 == null || p2 == null) {
  693. throw new SyntaxError("Invalid expression symbol");
  694. }
  695. return p2.compareTo(p1) < 0;
  696. }
  697.  
  698. private Result calc(List<Token> tokens, int index) throws SyntaxError
  699. {
  700. if (index >= tokens.size()) {
  701. throw new SyntaxError(tokens, index);
  702. }
  703.  
  704. Deque<Result> r_stack = new ArrayDeque<Result>();
  705. Deque<String> s_stack = new ArrayDeque<String>();
  706. int sign = 0;
  707. int flag = 0;
  708. Result temp, temp2;
  709.  
  710. for (; index < tokens.size(); index++) {
  711. Token cur = tokens.get(index);
  712. TokenType type = cur.getType();
  713. String token = cur.getToken();
  714.  
  715. if (flag == 0) {
  716. flag = 1;
  717. switch (type) {
  718. case SYMBL:
  719. if (sign != 0) {
  720. throw new SyntaxError(tokens, index);
  721. }
  722. if ("+".equals(token)) {
  723. sign = 1;
  724. } else if ("-".equals(token)) {
  725. sign = -1;
  726. } else {
  727. throw new SyntaxError(tokens, index);
  728. }
  729. flag = 0;
  730. break;
  731. case INT:
  732. r_stack.push(checksign(new Result(Integer.parseInt(token), index), sign));
  733. break;
  734. case DBL:
  735. r_stack.push(checksign(new Result(Double.parseDouble(token), index), sign));
  736. break;
  737. case STR:
  738. r_stack.push(checksign(new Result(token.substring(1, token.length() - 1), index), sign));
  739. break;
  740. case OP_BRKT:
  741. temp = calc(tokens, index + 1);
  742. index = temp.getOffset();
  743. if (TokenType.CL_BRKT.equals(tokens.get(index).getType()) == false) {
  744. throw new SyntaxError(tokens, index);
  745. }
  746. r_stack.push(checksign(temp, sign));
  747. break;
  748. case NAME:
  749. if (functionnames.contains(token)) {
  750. temp = doFunction(tokens, index);
  751. index = temp.getOffset();
  752. r_stack.push(checksign(temp, sign));
  753. } else if (strarrs.containsKey(token)) {
  754. temp = get_strarr(tokens, index);
  755. index = temp.getOffset();
  756. r_stack.push(checksign(temp, sign));
  757. } else if (strvars.containsKey(token)) {
  758. r_stack.push(checksign(new Result(strvars.get(token), index), sign));
  759. } else if (numarrs.containsKey(token)) {
  760. temp = get_numarr(tokens, index);
  761. index = temp.getOffset();
  762. r_stack.push(checksign(temp, sign));
  763. } else if (numvars.containsKey(token)) {
  764. r_stack.push(checksign(new Result(numvars.get(token), index), sign));
  765. } else if (checkKeyword(token)) {
  766. throw new SyntaxError("Invalid name");
  767. } else if (token.lastIndexOf("$") > 0) {
  768. // 未定義 文字列 変数
  769. if (index + 1 < tokens.size() && "(".equals(tokens.get(index + 1).getToken())) {
  770. // 配列
  771. List<Integer> dims = new ArrayList<Integer>();
  772. dims.add(Integer.valueOf(10));
  773. VarArray arr = new VarArray(dims);
  774. arr.setType(VarArrayType.STR);
  775. strarrs.put(tokens.get(index).getToken(), arr);
  776. temp = get_strarr(tokens, index);
  777. index = temp.getOffset();
  778. r_stack.push(checksign(temp, sign));
  779. } else {
  780. strvars.put(token, "");
  781. r_stack.push(checksign(new Result("", index), sign));
  782. }
  783. } else {
  784. // 未定義 数値 変数
  785. if (index + 1 < tokens.size() && "(".equals(tokens.get(index + 1).getToken())) {
  786. // 配列
  787. List<Integer> dims = new ArrayList<Integer>();
  788. dims.add(Integer.valueOf(10));
  789. VarArray arr = new VarArray(dims);
  790. arr.setType(VarArrayType.INT);
  791. numarrs.put(tokens.get(index).getToken(), arr);
  792. temp = get_numarr(tokens, index);
  793. index = temp.getOffset();
  794. r_stack.push(checksign(temp, sign));
  795. } else {
  796. numvars.put(token, Integer.valueOf(0));
  797. r_stack.push(checksign(new Result((int)0, index), sign));
  798. }
  799. }
  800. break;
  801. default:
  802. throw new SyntaxError(tokens, index);
  803. }
  804. } else if (flag == 1) {
  805. flag = 0;
  806. sign = 0;
  807. switch (type) {
  808. case NAME:
  809. switch (token) {
  810. case "OR":
  811. case "AND":
  812. temp = r_stack.peek();
  813. if (ResultType.STR.equals(temp.getType())) {
  814. throw new ExcuteError("Invalid expression symbol");
  815. }
  816. break;
  817. default:
  818. throw new SyntaxError(tokens, index);
  819. }
  820. case SYMBL:
  821. switch (token) {
  822. case "-":
  823. case "*":
  824. case "/":
  825. temp = r_stack.peek();
  826. if (ResultType.STR.equals(temp.getType())) {
  827. throw new ExcuteError("Invalid expression symbol");
  828. }
  829. default:
  830. break;
  831. }
  832. while (s_stack.size() > 0 && calccheck(s_stack.peek(), token)) {
  833. if (r_stack.size() < 2) {
  834. throw new ExcuteError("Unknown error");
  835. }
  836. temp2 = r_stack.pop();
  837. temp = r_stack.pop();
  838. temp = calc2(temp, temp2, s_stack.pop());
  839. r_stack.push(temp);
  840. }
  841. s_stack.push(token);
  842. break;
  843. case COLON:
  844. case SEMICOLON:
  845. case COMMA:
  846. case CL_BRKT:
  847. while (s_stack.size() > 0) {
  848. if (r_stack.size() < 2) {
  849. throw new ExcuteError("Unknown error");
  850. }
  851. temp2 = r_stack.pop();
  852. temp = r_stack.pop();
  853. temp = calc2(temp, temp2, s_stack.pop());
  854. r_stack.push(temp);
  855. }
  856. if (r_stack.size() != 1) {
  857. throw new ExcuteError("Unknown error");
  858. }
  859. temp = r_stack.pop();
  860. temp.setOffset(index);
  861. return temp;
  862. default:
  863. throw new SyntaxError(tokens, index);
  864. }
  865. }
  866. }
  867.  
  868.  
  869. if (flag == 0) {
  870. if (r_stack.size() > 0 || s_stack.size() > 0) {
  871. System.out.println("hoge");
  872. throw new SyntaxError(tokens, index);
  873. }
  874. return Result.getEOL(index);
  875. }
  876.  
  877. while (s_stack.size() > 0) {
  878. if (r_stack.size() < 2) {
  879. throw new ExcuteError("Unknown error");
  880. }
  881. temp2 = r_stack.pop();
  882. temp = r_stack.pop();
  883. temp = calc2(temp, temp2, s_stack.pop());
  884. r_stack.push(temp);
  885. }
  886. if (r_stack.size() != 1) {
  887. throw new ExcuteError("Unknown error");
  888. }
  889. temp = r_stack.pop();
  890. temp.setOffset(index);
  891. return temp;
  892. }
  893.  
  894. public Result get_strarr(List<Token> tokens, int index) throws SyntaxError
  895. {
  896. if (index + 3 >= tokens.size()) {
  897. throw new SyntaxError(tokens, index);
  898. }
  899. String name = tokens.get(index).getToken();
  900. index++;
  901. if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
  902. throw new SyntaxError(tokens, index);
  903. }
  904. index++;
  905. List<Integer> indexes = new ArrayList<Integer>();
  906. for (; index < tokens.size(); index++) {
  907. Result temp = calc(tokens, index);
  908. switch (temp.getType()) {
  909. case INT: indexes.add(Integer.valueOf(temp.getIntValue())); break;
  910. case DBL: indexes.add(Integer.valueOf(temp.getNumValue().intValue())); break;
  911. default: throw new SyntaxError(tokens, index);
  912. }
  913. index = temp.getOffset();
  914. if (index >= tokens.size()) {
  915. throw new SyntaxError(tokens, index);
  916. }
  917. switch (tokens.get(index).getType()) {
  918. case COMMA:
  919. break;
  920. case CL_BRKT:
  921. Result rs = new Result(strarrs.get(name).getStr(indexes, arraybase));
  922. rs.setOffset(index);
  923. return rs;
  924. default:
  925. throw new SyntaxError(tokens, index);
  926. }
  927. }
  928. throw new SyntaxError(tokens, index);
  929. }
  930.  
  931. public Result get_numarr(List<Token> tokens, int index) throws SyntaxError
  932. {
  933. if (index + 3 >= tokens.size()) {
  934. throw new SyntaxError(tokens, index);
  935. }
  936. String name = tokens.get(index).getToken();
  937. index++;
  938. if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
  939. throw new SyntaxError(tokens, index);
  940. }
  941. index++;
  942. List<Integer> indexes = new ArrayList<Integer>();
  943. for (; index < tokens.size(); index++) {
  944. Result temp = calc(tokens, index);
  945. switch (temp.getType()) {
  946. case INT: indexes.add(Integer.valueOf(temp.getIntValue())); break;
  947. case DBL: indexes.add(Integer.valueOf(temp.getNumValue().intValue())); break;
  948. default: throw new SyntaxError(tokens, index);
  949. }
  950. index = temp.getOffset();
  951. if (index >= tokens.size()) {
  952. throw new SyntaxError(tokens, index);
  953. }
  954. switch (tokens.get(index).getType()) {
  955. case COMMA:
  956. break;
  957. case CL_BRKT:
  958. VarArray arr = numarrs.get(name);
  959. Result rs = null;
  960. switch (arr.getType()) {
  961. case UNKNOWN:
  962. arr.setType(VarArrayType.INT);
  963. case INT:
  964. rs = new Result(arr.getInt(indexes, arraybase));
  965. break;
  966. case DBL:
  967. rs = new Result(arr.getDbl(indexes, arraybase));
  968. break;
  969. default:
  970. throw new ExcuteError("Unknown error");
  971. }
  972. rs.setOffset(index);
  973. return rs;
  974. default:
  975. throw new SyntaxError(tokens, index);
  976. }
  977. }
  978. throw new SyntaxError(tokens, index);
  979. }
  980.  
  981. public Result doFunction(List<Token> tokens, int index) throws SyntaxError
  982. {
  983. if (index + 1 >= tokens.size()) {
  984. throw new SyntaxError(tokens, index);
  985. }
  986. if (TokenType.OP_BRKT.equals(tokens.get(index + 1).getType()) == false) {
  987. throw new SyntaxError(tokens, index);
  988. }
  989. String name = tokens.get(index).getToken();
  990. Result temp;
  991. switch (name) {
  992. case "INT":
  993. temp = calc(tokens, index + 2);
  994. index = temp.getOffset();
  995. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  996. switch (temp.getType()) {
  997. case INT:
  998. return temp;
  999. case DBL:
  1000. return new Result(temp.getNumValue().intValue(), index);
  1001. default:
  1002. break;
  1003. }
  1004. }
  1005. throw new SyntaxError(tokens, index);
  1006. case "RND":
  1007. temp = calc(tokens, index + 2);
  1008. index = temp.getOffset();
  1009. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  1010. switch (temp.getType()) {
  1011. case INT:
  1012. case DBL:
  1013. int s = temp.getNumValue().intValue();
  1014. if (s == 0) {
  1015. return new Result(lastrand = rand.nextDouble(), index);
  1016. } else if (s > 0) {
  1017. rand.setSeed((long)s);
  1018. lastrand = rand.nextDouble();
  1019. }
  1020. return new Result(lastrand, index);
  1021. default:
  1022. break;
  1023. }
  1024. }
  1025. throw new SyntaxError(tokens, index);
  1026. case "CLK":
  1027. temp = calc(tokens, index + 2);
  1028. index = temp.getOffset();
  1029. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  1030. switch (temp.getType()) {
  1031. case INT:
  1032. case DBL:
  1033. double t = temp.getNumValue().doubleValue();
  1034. t -= Math.floor(t);
  1035. t *= 24;
  1036. return new Result((int)t, index);
  1037. default:
  1038. break;
  1039. }
  1040. }
  1041. throw new SyntaxError(tokens, index);
  1042. case "ABS":
  1043. temp = calc(tokens, index + 2);
  1044. index = temp.getOffset();
  1045. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  1046. switch (temp.getType()) {
  1047. case INT:
  1048. return new Result(Math.abs(temp.getIntValue()), index);
  1049. case DBL:
  1050. return new Result(Math.abs(temp.getDblValue()), index);
  1051. default:
  1052. break;
  1053. }
  1054. }
  1055. throw new SyntaxError(tokens, index);
  1056. case "VAL":
  1057. temp = calc(tokens, index + 2);
  1058. index = temp.getOffset();
  1059. if (TokenType.CL_BRKT.equals(tokens.get(index).getType())) {
  1060. switch (temp.getType()) {
  1061. case STR:
  1062. Matcher mt;
  1063. if ((mt = Pattern.compile("^(\\d*\\.\\d+)").matcher(temp.getStrValue())).lookingAt()) {
  1064. return new Result(Double.parseDouble(mt.group(1)), index);
  1065. } else if ((mt = Pattern.compile("^(\\d+)").matcher(temp.getStrValue())).lookingAt()) {
  1066. return new Result(Integer.parseInt(mt.group(1)), index);
  1067. } else {
  1068. return new Result(0.0, index);
  1069. }
  1070. default:
  1071. break;
  1072. }
  1073. }
  1074. throw new SyntaxError(tokens, index);
  1075. default:
  1076. break;
  1077. }
  1078.  
  1079. return Result.getEOL(index);
  1080. }
  1081.  
  1082. public int doEditorCommand(List<Token> tokens) throws SyntaxError
  1083. {
  1084. if (tokens == null || tokens.isEmpty()) {
  1085. return 0;
  1086. }
  1087.  
  1088. Token first = tokens.get(0);
  1089. String token = first.getToken();
  1090. TokenType type = first.getType();
  1091.  
  1092. if (TokenType.INT.equals(type)) {
  1093. Integer tmpint = Integer.valueOf(token);
  1094. if (tmpint.intValue() < 1) {
  1095. throw new SyntaxError(token);
  1096. }
  1097. if (tokens.size() > 1) {
  1098. program.put(tmpint, tokens);
  1099. } else {
  1100. program.remove(tmpint);
  1101. }
  1102. return 0;
  1103. } else if (TokenType.NAME.equals(type) == false) {
  1104. throw new ExcuteError(token);
  1105. }
  1106.  
  1107. /* */
  1108. if (Debug.isIDEONE()) {
  1109. printLine(null, tokens); // IDEONE上じゃ入力が見えないので
  1110. }
  1111. /* */
  1112.  
  1113. switch (token) {
  1114. case "CONT": // プログラムの再開
  1115. // TODO 処理
  1116. break;
  1117. case "EXIT": // インタプリタの終了
  1118. return -1;
  1119. case "LIST": // プログラムの表示
  1120. do_list(tokens);
  1121. break;
  1122. case "LOAD": // プログラムのロード
  1123. // TODO 処理
  1124. break;
  1125. case "NEW": // プログラムと変数の全消去
  1126. // TODO 処理
  1127. break;
  1128. case "RENUM": // プログラムの行番号再割り当て
  1129. // TODO 処理
  1130. break;
  1131. case "RUN": // プログラムの実行
  1132. do_run(tokens);
  1133. break;
  1134. case "SAVE": // プログラムの保存
  1135. // TODO 処理
  1136. break;
  1137. default:
  1138. excute(tokens, 0);
  1139. break;
  1140. }
  1141. if (stopflag) {
  1142. System.out.println("Stop");
  1143. stopflag = false;
  1144. return 0;
  1145. }
  1146. System.out.println("Ok");
  1147. return 0;
  1148. }
  1149.  
  1150. private void do_list(List<Token> tokens) throws SyntaxError
  1151. {
  1152. Integer start = null;
  1153. Integer end = null;
  1154. Token first, second, third;
  1155. Map<Integer, List<Token>> list = null;
  1156. try {
  1157. switch (tokens.size()) {
  1158. case 1:
  1159. list = program;
  1160. break;
  1161. case 2:
  1162. first = tokens.get(1);
  1163. if (TokenType.INT.equals(first.getType()) == false) {
  1164. throw new SyntaxError(tokens ,1);
  1165. }
  1166. end = start = Integer.valueOf(first.getToken());
  1167. if (start.intValue() < 1) {
  1168. throw new SyntaxError(tokens ,1);
  1169. }
  1170. list = program.subMap(start, true, end, true);
  1171. break;
  1172. case 3:
  1173. first = tokens.get(1);
  1174. second = tokens.get(2);
  1175. if ("-".equals(first.getToken())) {
  1176. if (TokenType.INT.equals(second.getType()) == false) {
  1177. throw new SyntaxError(tokens ,2);
  1178. }
  1179. end = Integer.valueOf(second.getToken());
  1180. if (end.intValue() < 1) {
  1181. throw new SyntaxError(tokens ,2);
  1182. }
  1183. list = program.headMap(end, true);
  1184. } else if (TokenType.INT.equals(first.getType())) {
  1185. start = Integer.valueOf(first.getToken());
  1186. if (start.intValue() < 1) {
  1187. throw new SyntaxError(tokens , 1);
  1188. }
  1189. if ("-".equals(second.getToken()) == false) {
  1190. throw new SyntaxError(tokens ,2);
  1191. }
  1192. list = program.tailMap(start);
  1193. } else {
  1194. throw new SyntaxError(tokens ,1);
  1195. }
  1196. break;
  1197. case 4:
  1198. first = tokens.get(1);
  1199. if (TokenType.INT.equals(first.getType()) == false) {
  1200. throw new SyntaxError(tokens ,1);
  1201. }
  1202. start = Integer.valueOf(first.getToken());
  1203. if (start.intValue() < 1) {
  1204. throw new SyntaxError(tokens ,1);
  1205. }
  1206. if ("-".equals(tokens.get(2).getToken()) == false) {
  1207. throw new SyntaxError(tokens ,2);
  1208. }
  1209. third = tokens.get(3);
  1210. if (TokenType.INT.equals(third.getType()) == false) {
  1211. throw new SyntaxError(tokens ,3);
  1212. }
  1213. end = Integer.valueOf(third.getToken());
  1214. if (end.intValue() < 1) {
  1215. throw new SyntaxError(tokens ,3);
  1216. }
  1217. list = program.subMap(start, true, end, true);
  1218. break;
  1219. default:
  1220. throw new SyntaxError(tokens, 0);
  1221. }
  1222. } catch (SyntaxError er) {
  1223. throw er;
  1224. } catch (Exception ex) {
  1225. throw new ExcuteError(ex);
  1226. }
  1227.  
  1228. if (list == null) {
  1229. return;
  1230. }
  1231.  
  1232. for (Integer key: list.keySet()) {
  1233. printLine(key, list.get(key));
  1234. }
  1235.  
  1236. }
  1237.  
  1238. private void do_run(List<Token> tokens) throws SyntaxError
  1239. {
  1240. switch (tokens.size()) {
  1241. case 1:
  1242. programcounter = program.ceilingKey(Integer.valueOf(1));
  1243. if (programcounter == null) {
  1244. throw new SyntaxError("Program is not found");
  1245. }
  1246. break;
  1247. case 2:
  1248. Token first = tokens.get(1);
  1249. if (TokenType.INT.equals(first.getType()) == false) {
  1250. throw new SyntaxError("Illegal Argument");
  1251. }
  1252. programcounter = Integer.valueOf(first.getToken());
  1253. if (programcounter.intValue() < 1) {
  1254. throw new SyntaxError("Wrong Line Number");
  1255. }
  1256. if (program.containsKey(programcounter) == false) {
  1257. throw new SyntaxError("Not found Line Number");
  1258. }
  1259. break;
  1260. default:
  1261. throw new SyntaxError("Illegal Arguments");
  1262. }
  1263.  
  1264. stopflag = endflag = false;
  1265. List<Token> line = null;
  1266. try {
  1267. while (programcounter != null) {
  1268. line = program.get(programcounter);
  1269. excute(line, 1);
  1270. if (jumpflag == false) {
  1271. programcounter = program.higherKey(programcounter);
  1272. if (stopflag) {
  1273. break;
  1274. } else if (endflag) {
  1275. break;
  1276. }
  1277. } else {
  1278. jumpflag = false;
  1279. }
  1280. }
  1281. } catch (SyntaxError er) {
  1282. printLine(line);
  1283. throw er;
  1284. }
  1285.  
  1286. }
  1287.  
  1288. private int excute(List<Token> tokens, int index) throws SyntaxError
  1289. {
  1290. if (index < 0 || index >= tokens.size()) {
  1291. return tokens.size();
  1292. }
  1293. Token first = tokens.get(index);
  1294. TokenType type = first.getType();
  1295.  
  1296. while (TokenType.COLON.equals(type)) {
  1297. index++;
  1298. if (index == tokens.size()) {
  1299. return index;
  1300. }
  1301. first = tokens.get(index);
  1302. type = first.getType();
  1303. }
  1304.  
  1305. if (TokenType.NAME.equals(type) == false) {
  1306. throw new SyntaxError(first.toString());
  1307. }
  1308. String cmd = first.getToken();
  1309. int offset = index;
  1310. switch (cmd) {
  1311. case "BASE": // 配列の下限(0/1)の設定
  1312. offset = cmd_base(tokens, index + 1);
  1313. break;
  1314. case "BREAK": // FORループの脱出
  1315. // TODO 処理
  1316. break;
  1317. case "DATA": // データの列挙
  1318. // TODO 処理
  1319. break;
  1320. case "DIM": // 配列変数の宣言
  1321. offset = cmd_dim(tokens, index + 1);
  1322. break;
  1323. case "ELSE": // IF文のELSE節の開始
  1324. // TODO 処理
  1325. break;
  1326. case "END": // プログラムの終了
  1327. endflag = true;
  1328. return tokens.size();
  1329. case "FILE": // ファイルの割り当て
  1330. // TODO 処理
  1331. break;
  1332. case "FOR": // 繰り返し
  1333. // TODO 処理
  1334. break;
  1335. case "GO": // GOTOの分割トークン
  1336. if (index + 2 >= tokens.size()) {
  1337. throw new SyntaxError(tokens, index);
  1338. }
  1339. if ("TO".equals(tokens.get(index + 1).getToken()) == false) {
  1340. throw new SyntaxError(tokens, index);
  1341. }
  1342. offset = cmd_goto(tokens, index + 2);
  1343. break;
  1344. case "GOTO": // ジャンプ
  1345. offset = cmd_goto(tokens, index + 1);
  1346. break;
  1347. case "GOSUB": // サブルーチンジャンプ
  1348. offset = cmd_gosub(tokens, index + 1);
  1349. break;
  1350. case "IF": // 条件節
  1351. // TODO 処理
  1352. break;
  1353. case "INPUT": // キーボードからの値の入力
  1354. // TODO 処理
  1355. break;
  1356. case "LET": // 変数への代入
  1357. offset = cmd_let(tokens, index + 1);
  1358. break;
  1359. case "NEXT": // FOR文の末端
  1360. // TODO 処理
  1361. break;
  1362. case "PRINT": // 画面へ値を出力
  1363. offset = cmd_print(tokens, index + 1);
  1364. break;
  1365. case "REM": // コメント行
  1366. offset = tokens.size();
  1367. break;
  1368. case "RESTORE": // データ・ファイルの読み込み位置のリセット
  1369. // TODO 処理
  1370. break;
  1371. case "RETURN": // サブルーチンからの脱出
  1372. offset = cmd_return(tokens, index);
  1373. break;
  1374. case "STOP": // プログラムの中断
  1375. stopflag = true;
  1376. return tokens.size();
  1377. default:
  1378. offset = cmd_let(tokens, index);
  1379. break;
  1380. }
  1381. return offset;
  1382. }
  1383.  
  1384. private int cmd_dim(List<Token> tokens, int index) throws SyntaxError
  1385. {
  1386. if (index + 3 >= tokens.size()) {
  1387. throw new SyntaxError(tokens, index);
  1388. }
  1389. List<Integer> dims = new ArrayList<Integer>();
  1390. int flag = 0;
  1391. Token cur = null;
  1392. String name = null;
  1393. for (; index < tokens.size(); index++) {
  1394. cur = tokens.get(index);
  1395. switch (flag) {
  1396. case 0:
  1397. if (TokenType.NAME.equals(cur.getType()) == false) {
  1398. throw new SyntaxError(tokens, index);
  1399. }
  1400. name = cur.getToken();
  1401. if (checkKeyword(name)) {
  1402. throw new SyntaxError("Invalid variable name:" + name);
  1403. }
  1404. flag = 1;
  1405. break;
  1406. case 1:
  1407. if (TokenType.OP_BRKT.equals(cur.getType()) == false) {
  1408. throw new SyntaxError(tokens, index);
  1409. }
  1410. dims.clear();
  1411. flag = 2;
  1412. break;
  1413. case 2:
  1414. if (TokenType.INT.equals(cur.getType()) == false) {
  1415. throw new SyntaxError(tokens, index);
  1416. }
  1417. Integer n = Integer.valueOf(cur.getToken());
  1418. if (n.intValue() < 1) {
  1419. throw new SyntaxError("Invalid dimention size");
  1420. }
  1421. dims.add(n);
  1422. flag = 3;
  1423. break;
  1424. case 3:
  1425. switch (cur.getType()) {
  1426. case COMMA:
  1427. flag = 2;
  1428. break;
  1429. case CL_BRKT:
  1430. VarArray temp = new VarArray(dims);
  1431. if (name.lastIndexOf("$") > 0) {
  1432. temp.setType(VarArrayType.STR);
  1433. strarrs.put(name, temp);
  1434. } else {
  1435. numarrs.put(name, temp);
  1436. }
  1437. flag = 4;
  1438. break;
  1439. default:
  1440. throw new SyntaxError(tokens, index);
  1441. }
  1442. break;
  1443. case 4:
  1444. switch (cur.getType()) {
  1445. case COMMA:
  1446. flag = 0;
  1447. break;
  1448. case COLON:
  1449. return excute(tokens, index);
  1450. default:
  1451. throw new SyntaxError(tokens, index);
  1452. }
  1453. break;
  1454. default:
  1455. throw new SyntaxError(tokens, index);
  1456. }
  1457. }
  1458. if (flag != 4) {
  1459. throw new SyntaxError(tokens, index);
  1460. }
  1461.  
  1462. return excute(tokens, index);
  1463. }
  1464.  
  1465. private int cmd_goto(List<Token> tokens, int index) throws SyntaxError
  1466. {
  1467. if (index >= tokens.size()) {
  1468. throw new SyntaxError(tokens, index);
  1469. }
  1470. if (index + 1 < tokens.size()) {
  1471. if (TokenType.COLON.equals(tokens.get(index + 1).getType()) == false) {
  1472. throw new SyntaxError(tokens, index + 1);
  1473. }
  1474. }
  1475. // TODO 未テスト コード
  1476. Token first = tokens.get(index);
  1477. if (TokenType.INT.equals(first.getType()) == false) {
  1478. throw new SyntaxError(tokens, index);
  1479. }
  1480. Integer next = Integer.valueOf(first.getToken());
  1481. if (program.containsKey(next) == false) {
  1482. throw new SyntaxError(tokens, index);
  1483. }
  1484. programcounter = next;
  1485. jumpflag = true;
  1486. return tokens.size();
  1487. }
  1488.  
  1489. private int cmd_gosub(List<Token> tokens, int index) throws SyntaxError
  1490. {
  1491. if (index >= tokens.size()) {
  1492. throw new SyntaxError(tokens, index);
  1493. }
  1494. if (index + 1 < tokens.size()) {
  1495. if (TokenType.COLON.equals(tokens.get(index + 1).getType()) == false) {
  1496. throw new SyntaxError(tokens, index + 1);
  1497. }
  1498. }
  1499. Token first = tokens.get(index);
  1500. if (TokenType.INT.equals(first.getType()) == false) {
  1501. throw new SyntaxError(tokens, index);
  1502. }
  1503. Integer next = Integer.valueOf(first.getToken());
  1504. if (program.containsKey(next) == false) {
  1505. throw new SyntaxError(tokens, index);
  1506. }
  1507. // TODO 未テスト コード
  1508. // WRONG CODE : RETURNはGOSUBの次の行だけじゃなく次の命令文(コロンがある)から始まることも
  1509. try {
  1510. programcounterstack.push(programcounter);
  1511. programcounter = next;
  1512. jumpflag = true;
  1513. return tokens.size();
  1514. } catch (Exception ex) {
  1515. throw new ExcuteError(ex);
  1516. }
  1517. }
  1518.  
  1519. private int cmd_return(List<Token> tokens, int index) throws SyntaxError
  1520. {
  1521. if (index < tokens.size()) {
  1522. if (TokenType.COLON.equals(tokens.get(index).getType()) == false) {
  1523. throw new SyntaxError(tokens, index);
  1524. }
  1525. }
  1526. // TODO 未テスト コード
  1527. // WRONG CODE : RETURNはGOSUBの次の行だけじゃなく次の命令文(コロンがある)から始まることも
  1528. try {
  1529. Integer back = programcounterstack.pop();
  1530. programcounter = program.higherKey(back);
  1531. jumpflag = true;
  1532. return tokens.size();
  1533. } catch (Exception ex) {
  1534. throw new ExcuteError(ex);
  1535. }
  1536. }
  1537.  
  1538.  
  1539. private int cmd_base(List<Token> tokens, int index) throws SyntaxError
  1540. {
  1541. // TODO 未テスト コード
  1542. // N-88 BASIC の OPTION BASE の場合は
  1543. // どのDIMよりも先に使う必要があり、プログラム中1回しか使えないらしい
  1544. try {
  1545. Token first = tokens.get(index);
  1546. if (TokenType.INT.equals(first.getType()) == false) {
  1547. throw new SyntaxError(tokens, index);
  1548. }
  1549. int tmpint = Integer.parseInt(first.getToken());
  1550. if (tmpint != 0 && tmpint != 1) {
  1551. throw new SyntaxError(tokens, index + 1);
  1552. }
  1553. arraybase = tmpint;
  1554. return excute(tokens, index + 1);
  1555. } catch (SyntaxError er) {
  1556. throw er;
  1557. } catch (Exception ex) {
  1558. throw new ExcuteError(ex);
  1559. }
  1560. }
  1561.  
  1562. private int cmd_print(List<Token> tokens, int index) throws SyntaxError
  1563. {
  1564. if (index == tokens.size()) {
  1565. tabcount = 0;
  1566. System.out.println();
  1567. return tokens.size();
  1568. } else if (index > tokens.size()) {
  1569. throw new ExcuteError("Unknown error");
  1570. }
  1571. StringBuilder output = new StringBuilder();
  1572. boolean nl = true;
  1573. for (; index < tokens.size(); index++) {
  1574. Token cur = tokens.get(index);
  1575. switch (cur.getType()) {
  1576. case COLON:
  1577. if (nl) {
  1578. tabcount = 0;
  1579. System.out.println(output);
  1580. } else {
  1581. tabcount += output.length();
  1582. System.out.print(output);
  1583. }
  1584. return excute(tokens, index + 1);
  1585. case COMMA:
  1586. output.append('\t');
  1587. nl = false;
  1588. break;
  1589. case SEMICOLON:
  1590. nl = false;
  1591. break;
  1592. case INT:
  1593. case DBL:
  1594. case STR:
  1595. case NAME:
  1596. Result temp = calc(tokens, index);
  1597. index = temp.getOffset() - 1;
  1598. switch (temp.getType()) {
  1599. case INT: output.append(temp.getIntValue()); break;
  1600. case DBL: output.append(temp.getDblValue()); break;
  1601. case STR: output.append(temp.getStrValue()); break;
  1602. default:
  1603. throw new ExcuteError("Unknown error");
  1604. }
  1605. nl = true;
  1606. break;
  1607. }
  1608. }
  1609. if (nl) {
  1610. tabcount = 0;
  1611. System.out.println(output);
  1612. } else {
  1613. tabcount += output.length();
  1614. System.out.print(output);
  1615. }
  1616. return excute(tokens, index);
  1617. }
  1618.  
  1619. private int getIndexes(List<Token> tokens, int index, List<Integer> indexes) throws SyntaxError
  1620. {
  1621. for (; index < tokens.size(); index++) {
  1622. Result temp = calc(tokens, index);
  1623. switch (temp.getType()) {
  1624. case INT: indexes.add(Integer.valueOf(temp.getIntValue())); break;
  1625. case DBL: indexes.add(Integer.valueOf(temp.getNumValue().intValue())); break;
  1626. default: throw new SyntaxError(tokens, index);
  1627. }
  1628. index = temp.getOffset();
  1629. switch (tokens.get(index).getType()) {
  1630. case COMMA:
  1631. break;
  1632. case CL_BRKT:
  1633. return index;
  1634. default:
  1635. throw new SyntaxError(tokens, index);
  1636. }
  1637. }
  1638. throw new SyntaxError(tokens, index);
  1639. }
  1640.  
  1641. private int cmd_let(List<Token> tokens, int index) throws SyntaxError
  1642. {
  1643. try {
  1644. if (index + 2 >= tokens.size()) {
  1645. throw new SyntaxError(tokens, index);
  1646. }
  1647. Token first = tokens.get(index);
  1648. String name = first.getToken();
  1649. if (checkKeyword(name)) { // 予約語チェック
  1650. throw new SyntaxError("Wrong variable name: " + name);
  1651. }
  1652. index++;
  1653. Result temp;
  1654. if (name.lastIndexOf("$") > 0) {
  1655. if (strarrs.containsKey(name)) {
  1656. if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
  1657. throw new SyntaxError(tokens, index);
  1658. }
  1659. index++;
  1660. List<Integer> indexes = new ArrayList<Integer>();
  1661. index = getIndexes(tokens, index, indexes);
  1662. index++;
  1663. if ("=".equals(tokens.get(index).getToken()) == false) {
  1664. throw new SyntaxError(tokens, index);
  1665. }
  1666. index++;
  1667. temp = calc(tokens, index);
  1668. if (ResultType.STR.equals(temp.getType()) == false) {
  1669. throw new ExcuteError("Invalid type value");
  1670. }
  1671. index = temp.getOffset();
  1672. strarrs.get(name).setStr(indexes, arraybase, temp.getStrValue());
  1673. } else {
  1674. if ("=".equals(tokens.get(index).getToken()) == false) {
  1675. throw new SyntaxError(tokens, index);
  1676. }
  1677. index++;
  1678. temp = calc(tokens, index);
  1679. if (ResultType.STR.equals(temp.getType()) == false) {
  1680. throw new ExcuteError("Invalid type value");
  1681. }
  1682. index = temp.getOffset();
  1683. strvars.put(name, temp.getStrValue());
  1684. }
  1685. } else {
  1686. if (numarrs.containsKey(name)) {
  1687. if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
  1688. throw new SyntaxError(tokens, index);
  1689. }
  1690. index++;
  1691. List<Integer> indexes = new ArrayList<Integer>();
  1692. index = getIndexes(tokens, index, indexes);
  1693. index++;
  1694. if ("=".equals(tokens.get(index).getToken()) == false) {
  1695. throw new SyntaxError(tokens ,index);
  1696. }
  1697. index++;
  1698. temp = calc(tokens, index);
  1699. index = temp.getOffset();
  1700. VarArray arr = numarrs.get(name);
  1701. switch (temp.getType()) {
  1702. case INT:
  1703. switch (arr.getType()) {
  1704. case UNKNOWN:
  1705. arr.setType(VarArrayType.INT);
  1706. case INT:
  1707. arr.setInt(indexes, arraybase, temp.getIntValue());
  1708. break;
  1709. case DBL:
  1710. arr.setDbl(indexes, arraybase, Double.valueOf(temp.getNumValue().doubleValue()));
  1711. break;
  1712. default:
  1713. throw new ExcuteError("Invalid type value");
  1714. }
  1715. break;
  1716. case DBL:
  1717. switch (arr.getType()) {
  1718. case UNKNOWN:
  1719. arr.setType(VarArrayType.DBL);
  1720. case DBL:
  1721. arr.setDbl(indexes, arraybase, temp.getDblValue());
  1722. break;
  1723. case INT:
  1724. arr.setInt(indexes, arraybase, Integer.valueOf(temp.getNumValue().intValue()));
  1725. break;
  1726. default:
  1727. throw new ExcuteError("Invalid type value");
  1728. } break;
  1729. default:
  1730. throw new ExcuteError("Invalid type value");
  1731. }
  1732. } else if (numvars.containsKey(name)) {
  1733. if ("=".equals(tokens.get(index).getToken()) == false) {
  1734. throw new SyntaxError(tokens ,index);
  1735. }
  1736. index++;
  1737. temp = calc(tokens, index);
  1738. index = temp.getOffset();
  1739. Number num = numvars.get(name);
  1740. switch (temp.getType()) {
  1741. case INT:
  1742. if (Integer.class.equals(num.getClass())) {
  1743. numvars.put(name, temp.getNumValue());
  1744. } else if (Double.class.equals(num.getClass())) {
  1745. numvars.put(name, Double.valueOf(temp.getNumValue().doubleValue()));
  1746. } else {
  1747. throw new ExcuteError("Invalid type value");
  1748. }
  1749. break;
  1750. case DBL:
  1751. if (Integer.class.equals(num.getClass())) {
  1752. numvars.put(name, Integer.valueOf(temp.getNumValue().intValue()));
  1753. } else if (Double.class.equals(num.getClass())) {
  1754. numvars.put(name, temp.getNumValue());
  1755. } else {
  1756. throw new ExcuteError("Invalid type value");
  1757. }
  1758. break;
  1759. default:
  1760. throw new ExcuteError("Invalid type value");
  1761. }
  1762. } else {
  1763. if ("=".equals(tokens.get(index).getToken()) == false) {
  1764. throw new SyntaxError(tokens, index);
  1765. }
  1766. index++;
  1767. temp = calc(tokens, index);
  1768. index = temp.getOffset();
  1769. switch (temp.getType()) {
  1770. case INT:
  1771. case DBL:
  1772. numvars.put(name, temp.getNumValue());
  1773. break;
  1774. default:
  1775. throw new ExcuteError("Invalid type value");
  1776. }
  1777. }
  1778. }
  1779. return excute(tokens, index + 1);
  1780. } catch (SyntaxError er) {
  1781. throw er;
  1782. } catch (Exception ex) {
  1783. // ex.printStackTrace();
  1784. throw new ExcuteError(tokens.toString());
  1785. }
  1786.  
  1787. }
  1788.  
  1789. }
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"
dim a(1), b(2,3), c$(5)
let c$(1)="hoge"
let a(1) =5.4
let b(1,1)=45
print c$(1), a(1), b(1,1), b(2,3), c$(5)
stdout
BASIC Interpreter - Version 0.4a
Your code goes here!

DIM A(1),B(2,3),C$(5)
Ok
LET C$(1)="hoge"
Ok
LET A(1)=5.4
Ok
LET B(1,1)=45
Ok
PRINT C$(1),A(1),B(1,1),B(2,3),C$(5)
hoge	5.4	45	0	
Ok