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