/** * * * * * * * * **/
//package JBasicShell;
import java.io.*;
// {{{ class JBasicShell
/** * * * * * * * **/
public class JBasicShell{ // {{{ main function /** * * * **/ public static void main(String[] args) { if (args.length == 0) { JBasicShell.runInteractive(); } else if (args.length == 1) { if (args[0].equals("-h")) { JBasicShell.help(); } else if (args[0].equals("-v")) { JBasicShell.version(); } else if (args[0].equals("-i")) { JBasicShell.runInteractive(); } else { JBasicShell.help(); } } else if (args.length == 2) { if (args[0].equals("-r")) { JBasicShell.run(args[1]); } else if (args[0].equals("-d")) { JBasicShell.runDebug(args[1]); } else { JBasicShell.help(); } } else { JBasicShell.help(); } }
// }}} // {{{ static void runInteractive()
/** * * * **/ private static void runInteractive() { } // }}} // {{{ static void run($source) /** * * * * **/ private static void run(String sourcefile) { String source = JBasicShell.loadSourcefile(sourcefile); JBasicCore jbsh = new JBasicCore(); jbsh.run(source, false); }
// }}} // {{{ static runDebug(String sourcefle) /** * * * * **/ private static void runDebug(String sourcefile) { String source = JBasicShell.loadSourcefile(sourcefile); JBasicCore jbsh = new JBasicCore(); jbsh.run(source, true); }
// }}}
// {{{ static loadSourcefile(String sourcefile) /** * * * * **/ private static String loadSourcefile(String sourcefile) { StringBuffer buffer = new StringBuffer(); FileReader fr = null;
try { fr = new FileReader(sourcefile); int i; while ((i = fr.read()) != -1) { buffer.append((char)i); } fr.close(); } catch (FileNotFoundException e) { System.out.println("This file isn't found."); } catch (IOException e) { System.out.println("It is exit since some execptions"); } return new String(buffer); }
// }}} // {{{ static void help() /** * * * **/ private static void help() { System.out.println("ok"); } // }}} // {{{ static void version() /** * * * * **/ private static void version() { }
// }}}}
// }}}
// {{{ class JBasicCore
/** * This is the main class in the 'JBasicShell', and is used in parsing * the code string of the Basic program.It be contain some constants * , variables and sub-classes for describing the struct of the Basic * code, and some methods for parsing and debugging the program code. * * @package JBasicShell * @category Language * @version 1.0.0 * **/
class JBasicCore{// {{{ sub-classes // {{{ class label /** * * * @access private **/ private class label { public String name = ""; public int pos = 0; } // }}} // {{{ class command /** * * * * @access private **/ private class command { public String name = ""; public int cmdNo = 0;
public command(String name, int cmdNo) { this.name = name; this.cmdNo = cmdNo; } } // {{{ class for_stack
/** * * * * * @access private **/ private class for_stack { int var = 0; int pos = 0; int target = 0; } // }}} // }}} // {{{ constant
/** * * * @access private **/ private static int NUM_LAB = 100;
/** * the keyword number in Basic language * * @var int * @static * @access private **/ private static int COMMAND_NUM = 13;
/** * * * @access private **/ private static int FOR_NEXT = 25;
/** * * * @access private **/ private static int SUB_NEXT = 25;
/** * * * @access private **/ private static int LETTER_NUM = 26;
/** * the command sign for running the keywork 'PRINT' * * @var int * @static * @access private **/ private static int ACTION_PRINT = 1;
/** * the command sign for running the keywork 'INPUT' * * @var int * @static * @access private **/ private static int ACTION_INPUT = 2;
/** * the command sign for running the keywork 'IF' * * @var int * @static * @access private **/ private static int ACTION_IF = 3;
/** * the command sign for running the keywork 'THEN' * * @var int * @static * @access private **/ private static int ACTION_THEN = 4;
/** * the command sign for running the keywork 'FOR' * * @var int * @static * @access private **/ private static int ACTION_FOR = 5;
/** * the command sign for running the keyword 'NEXT' * * @var int * @static * @access private **/ private static int ACTION_NEXT = 6;
/** * the command sign for running the keyword 'TO' * * @var int * @static * @access private **/ private static int ACTION_TO = 7;
/** * the command sign for running the keyword 'GOTO' * * @var int * @static * @access private **/ private static int ACTION_GOTO = 8;
/** * the command sign for running when see 'EOL' sign * * @var int * @static * @access private **/ private static int ACTION_EOL = 9;
/** * the command sign for running when finish parsing * * @var int * @static * @access private **/ private static int ACTION_FINISHED = 10;
/** * the command sign for running the keyword 'gosub' * * @var int * @static * @access private **/ private static int ACTION_GOSUB = 11;
/** * the command sign for running the keyword 'return' * * @var int * @static * @access private **/ private static int ACTION_RETURN = 12;
/** * the command sign for running the keyword 'end' * * @var int * @static * @access private **/ private static int ACTION_END = 13;
/** * the command sign for running the keyword 'system' * * @var int * @static * @access private **/ private static int ACTION_SYSTEM = 14; /** * the parsing-item type for 'delimiter' * * @var int * @static * @access private **/ private static int WORDTYPE_DELIMITER = 1;
/** * the parsing-item type for 'variable' * * @var int * @static * @access private **/ private static int WORDTYPE_VARIABLE = 2;
/** * the parsing-item type for 'number' * * @var int * @static * @access private **/ private static int WORDTYPE_NUMBER = 3;
/** * the parsing-item type for 'command' * * @var int * @static * @access private **/ private static int WORDTYPE_COMMAND = 4;
/** * the parsing-item type for 'string' * * @var int * @static * @access private **/ private static int WORDTYPE_STRING = 5;
/** * the parsing-item type for 'quote' * * @var int * @static * @access private **/ private static int WORDTYPE_QUOTE = 6;
// }}} // {{{ variables /** * * * @access private **/ private label[] label_table = new label[this.NUM_LAB];
/** * * * @access private **/ private command[] command_table = new command[this.COMMAND_NUM];
/** * * * @access private **/ private for_stack[] fstack = new for_stack[this.FOR_NEXT];
/** * * * @access private **/ private int[] gstack = new int[this.SUB_NEXT];
/** * * * @access private **/ private int[] variables = new int[this.LETTER_NUM];
/** * * * @access private **/ private String proc_contents = "";
/** * * * @access private **/ private int proc_position = 0;
/** * * * @access private **/ private int proc_wordtype = 0;
/** * * * @access private **/ private int proc_action = 0;
/** * * * @access private **/ private String strBuffer_new = "";
/** * * * @access private **/ private String strBuffer_old = "";
/** * * * @access private **/ private int ftop = 0;
/** * * * @access private **/ private int gtop = 0;
/** * * * @access private **/ private boolean debug = false;
// }}} // {{{ constructor /** * * * * **/ public JBasicCore() { this.initCommand(); } // }}} // {{{ void initCommand() /** * initalize the command keyword string * * @access private **/ private void initCommand() { this.command_table[0] = new command("print", this.ACTION_PRINT); this.command_table[1] = new command("input", this.ACTION_INPUT); this.command_table[2] = new command("if", this.ACTION_IF); this.command_table[3] = new command("then", this.ACTION_THEN); this.command_table[4] = new command("goto", this.ACTION_GOTO); this.command_table[5] = new command("for", this.ACTION_FOR); this.command_table[6] = new command("next", this.ACTION_NEXT); this.command_table[7] = new command("to", this.ACTION_TO); this.command_table[8] = new command("gosub", this.ACTION_GOSUB); this.command_table[9] = new command("return", this.ACTION_RETURN); this.command_table[10] = new command("end", this.ACTION_END); this.command_table[11] = new command("system", this.ACTION_SYSTEM); this.command_table[12] = new command("", this.ACTION_END); }
// }}} // {{{ void run(String source) /** * run the language parsing for Basic code, and support the debug mode and * immediate-running mode. * * @param string the source string of the Basic language * * @param boolean it is in the debug mode if true, * else it is immediate-running mode * * @access public **/ public void run(String source, boolean debug) { this.proc_contents = source; this.debug = debug;
this.scanLabel(); do { this.checkCurrChar(); if (this.proc_wordtype == this.WORDTYPE_VARIABLE) { this.putBack(); this.assignment(); } else { if (this.proc_action == this.ACTION_PRINT) { this.execPrint(); } else if (this.proc_action == this.ACTION_GOTO) { this.execGoto(); } else if (this.proc_action == this.ACTION_IF) { this.execIf(); } else if (this.proc_action == this.ACTION_FOR) { this.execFor(); } else if (this.proc_action == this.ACTION_NEXT) { this.execNext(); } else if (this.proc_action == this.ACTION_INPUT) { this.execInput(); } else if (this.proc_action == this.ACTION_GOSUB) { this.execGosub(); } else if (this.proc_action == this.ACTION_RETURN) { this.execReturn(); } else if (this.proc_action == this.ACTION_SYSTEM) { this.execSystem(); } else if (this.proc_action == this.ACTION_END) { this.execEnd(); } else {} } } while(this.proc_action != this.ACTION_FINISHED); }
// }}} // {{{ void scanLabel() /** * * * * * **/ private void scanLabel() { int tmp = this.proc_position;
this.checkCurrChar(); if (this.proc_wordtype == this.WORDTYPE_NUMBER) { label_table[0].name = this.strBuffer_new; label_table[0].pos = this.proc_position; } this.findEOL();
do { this.checkCurrChar(); if (this.proc_wordtype == this.WORDTYPE_NUMBER) { int addr = this.getNextLabel(this.strBuffer_new); if (addr == -1) { this.showError(5); } else if (addr == -2) { this.showError(6); } else { } } if (this.proc_action != this.ACTION_EOL) { this.findEOL(); } } while(this.proc_action != this.ACTION_FINISHED);
this.proc_position = tmp; }
// }}} // {{{ void findEOL() /** * * * * **/ private void findEOL() { char curr_char = 0; int len = this.proc_contents.length();
while (curr_char != '/r' && curr_char != '/n' && this.proc_position < len) { curr_char = this.proc_contents.charAt(this.proc_position); this.proc_position++; }
if (this.proc_position < len) { this.proc_position++; } }
// }}} // {{{ int getNextLabel(String str) /** * * * * **/ private int getNextLabel(String str) { for (int t = 0; t < NUM_LAB; t++) { String name = this.label_table[t].name; if (name.equals("")) { return t; } if (name.equals(str)) { return -2; } }
return -1; }
// }}} // {{{ int findLabel(String str) /** * * * * **/ private int findLabel(String str) { for (int t = 0; t < this.NUM_LAB; t++) { if (str.equals(this.label_table[t].name)) { return this.label_table[t].pos; } }
return -1; }
// }}} // {{{ void execPrint() /** * * * * **/ private void execPrint() { int answer = 0; int len = 0; int space = 0; char last = 0;
do { this.checkCurrChar();
if (this.proc_action == this.ACTION_EOL || this.proc_action == this.ACTION_FINISHED) { break; }
if (this.proc_wordtype == this.WORDTYPE_QUOTE) { System.out.print(this.strBuffer_new); len += this.strBuffer_new.length(); this.checkCurrChar(); } else { this.putBack(); answer = this.getExp(answer); System.out.print(answer); len += answer; this.checkCurrChar(); } last = this.strBuffer_new.charAt(0); // if (last == ';') { space = 8 - (len % 8); len += space;
while (space != 0) { System.out.print(" "); space--; } } else if (last == ',') { } else if (this.proc_action == this.ACTION_EOL || this.proc_action == this.ACTION_FINISHED) { this.showError(0); } } while(last == ';' || last == ',');
if (this.proc_action == this.ACTION_EOL || this.proc_action == this.ACTION_FINISHED) { if (last != ';' && last != ',') { System.out.print("/n"); } } else { this.showError(0); } }
// }}} // {{{ void execGoto() /** * * * * **/
private void execGoto() { this.checkCurrChar(); int pos = this.findLabel(this.strBuffer_new); if (pos < 0) { this.showError(7); } else { this.proc_position = pos; } } // }}} // {{{ void execIf() /** * * * * * **/ private void execIf() { int x = 0; x = this.getExp(x); //this.checkExp(); char tmp = this.strBuffer_new.charAt(0); //
if ("=<>".indexOf(tmp) >= 0) { this.showError(0); return; } char op = tmp;
int y = 0; y = this.getExp(y);
boolean cond = false; switch (op) { case '<': if (x < y) { cond = true; } break; case '>': if (x > y) { cond = true; } break; case '=': if (x == y) { cond = true; } break; }
if (cond) { this.checkCurrChar(); if (this.proc_action != this.ACTION_THEN) { this.showError(8); return; } } else { this.findEOL(); } }
// }}} // {{{ void execFor() /** * * * * * **/ private void execFor() { for_stack i = new for_stack(); int value = 0;
this.checkCurrChar(); if (!Character.isLetter(this.strBuffer_new.charAt(0))) { this.showError(4); return; }
char ch = this.strBuffer_new.toUpperCase().charAt(0); i.var = Integer.valueOf(ch - 'A');
this.checkCurrChar(); char op = this.strBuffer_new.charAt(0); if (op != '=') { this.showError(3); return; }
value = this.getExp(value); this.variables[i.var] = value;
this.checkCurrChar(); if (this.proc_action != this.ACTION_TO) { this.showError(9); } i.target = this.getExp(i.target);
if (value >= this.variables[i.var]) { i.pos = this.proc_position; this.fpush(i); } else { while (this.proc_action != this.ACTION_NEXT) { this.checkCurrChar(); } } }
// }}} // {{{ void execNext() /** * * * * * * **/ private void execNext() { for_stack i = new for_stack(); i = this.fpop(); this.variables[i.var]++;
if (this.variables[i.var] > i.target) { return; }
this.fpush(i); this.proc_position = i.pos; }
// }}} // {{{ execGosub() /** * * * * * **/ private void execGosub() { this.checkCurrChar(); int loc = this.findLabel(this.strBuffer_new);
if (loc < 0) { this.showError(7); } else { this.gpush(this.proc_position); this.proc_position = loc; } }
// }}} // {{{ void execInput() /** * * * * **/ private void execInput() { this.checkCurrChar(); if (this.proc_wordtype == this.WORDTYPE_QUOTE) { System.out.print(this.strBuffer_new); this.checkCurrChar(); char op = this.strBuffer_new.charAt(0); if (op != ',') { this.showError(1); } this.checkCurrChar(); } else { System.out.print("?"); } char ch = this.strBuffer_new.toUpperCase().charAt(0); int var = Integer.valueOf(ch - 'A'); int inp = 0; // this.variables[var] = inp; }
// }}} // {{{ void execReturn() /** * * * **/ private void execReturn() { this.proc_position = this.gpop(); }
// }}} // {{{ void execSystem() /** * * * **/ private void execSystem() { }
// {{{ void execEnd() /** * * * * **/ private void execEnd() { }
// }}} // {{{ void gpush(int position) /** * * * * **/ private void gpush(int position) { this.gtop++; if (this.gtop == this.SUB_NEXT) { this.showError(12); return; } this.gstack[this.gtop] = position; }
// }}} // {{{ int gpop() /** * * * **/ private int gpop() { if (this.gtop == 0) { this.showError(13); return 0; } int ret = this.gstack[this.gtop]; this.gtop--; return ret; }
// }}} // {{{ void fpush(for_stack i)
/** * * * * **/ private void fpush(for_stack i) { if (this.ftop > this.FOR_NEXT) { this.showError(0); }
this.fstack[ftop] = i; this.ftop++; } // }}} // {{{ for_stack fpop() /** * * * * **/ private for_stack fpop() { this.ftop--;
if (ftop < 0) { this.showError(11); }
return this.fstack[ftop]; }
// }}} // {{{ int getExp(number) /** * * * * * **/ private int getExp(int number) { int result = number; this.checkCurrChar();
if (this.strBuffer_new.equals("")) { this.showError(2); return result; }
result = this.levelII(result); this.putBack();
return result; }
// }}} // {{{ int levelII(int number) /** * * * **/ private int levelII(int number) { int result = this.levelIII(number); int hold = 0; char op = this.strBuffer_new.charAt(0);
while (op == '+' || op == '-') { this.checkCurrChar(); hold = this.levelIII(hold); result = this.arith(op, result, hold); }
return result; }
// }}} // {{{ int levelIII(int number) /** * * * * * **/ private int levelIII(int number) { int result = this.levelIV(number); int hold = 0; char op = this.strBuffer_new.charAt(0);
while (op == '*' || op == '/' || op == '%') { this.checkCurrChar(); hold = this.levelIV(hold); result = this.arith(op, result, hold); }
return result; }
// }}} // {{{ int levelIV(int number) /** * * * **/ private int levelIV(int number) { int result = this.levelV(number); int hold = 0; char op = this.strBuffer_new.charAt(0);
if (op == '^') { this.checkCurrChar(); hold = this.levelIV(hold); result = this.arith('^', result, hold); }
return result; }
// }}} // {{{ int levelV(int number) /** * * * * **/ private int levelV(int number) { char op = 0; char tmp = this.strBuffer_new.charAt(0);
if ((this.proc_wordtype == this.WORDTYPE_DELIMITER) && (tmp == '+' || tmp == '-')) { op = tmp; this.checkCurrChar(); } int result = this.levelVI(number); if (op == 0) { result = this.unary(op, result); }
return result; }
// }}} // {{{ int levelVI(int number)
/** * * * **/ private int levelVI(int number) { char op = this.strBuffer_new.charAt(0); int result = 0;
if ((this.proc_wordtype == this.WORDTYPE_DELIMITER) && (op == '(')) { this.checkCurrChar(); result = this.levelII(number); op = this.strBuffer_new.charAt(0); if (op != ')') { this.showError(1); return result; } this.checkCurrChar(); } else { result = this.primitive(number); }
return result; }
// }}} // {{{ int primitive(number) /** * * * * **/ private int primitive(int number) { int result = number;
if (this.proc_wordtype == this.WORDTYPE_VARIABLE) { result = this.findVar(this.strBuffer_new.charAt(0)); this.checkCurrChar(); } else if (this.proc_wordtype == this.WORDTYPE_NUMBER) { result = Integer.valueOf(this.strBuffer_new); this.checkCurrChar(); } else { this.showError(0); }
return result; }
// }}} // {{{ int unary(char op, int number) /** * * * * **/ private int unary(char op, int number) { int result = number;
if (op == '-') { result = 0 - number; }
return result; }
// }}} // {{{ void putBack() /** * * * * **/ private void putBack() { this.proc_position -= this.strBuffer_new.length(); }
// }}} // {{{ int arith(char op, int number_i, int number_ii) /** * * * * * **/ private int arith(char op, int number_i, int number_ii) { int result = 0; switch (op) { case '-': result = number_i - number_ii; break; case '+': result = number_i + number_ii; break; case '*': result = number_i * number_ii; break; case '/': result = (int)(number_i / number_ii); break; case '%': result = number_i % number_ii; break; case '^': if (number_ii < 0) { result = 0; } else if (number_ii == 0) { result = 1; } else { result = number_i; for (int t = number_ii -1; t > 0; t--) { result = number_i * result; } } break; } return result; }
// }}} // {{{ void checkCurrChar() /** * check the current char in the source string for getting the * parsing item, such as command, variable and others * * @access private **/ private void checkCurrChar() { /** * check the last char in the source string to exit parsing **/ if (this.proc_position >= (this.proc_contents.length() - 1)) { this.strBuffer_new = ""; this.proc_action = this.ACTION_FINISHED; this.proc_wordtype = this.WORDTYPE_DELIMITER; return; }
this.strBuffer_old = this.strBuffer_new; char curr_char = this.proc_contents.charAt(this.proc_position);
/** * check the blank space to ignore it **/ while (this.isWhite(curr_char)) { this.proc_position++; }
/** * check that this char is a 'EOL' for Windows **/ if (curr_char == '/r') { this.strBuffer_new = "/r/n"; this.proc_action = this.ACTION_EOL; this.proc_wordtype = this.WORDTYPE_DELIMITER; this.proc_position += 2; return; }
/** * check that this char is a 'EOL' for UNIX/Linux **/ if (curr_char == '/n') { this.strBuffer_new = "/n"; this.proc_action = this.ACTION_EOL; this.proc_wordtype = this.WORDTYPE_DELIMITER; this.proc_position++; return; }
/** * check that this char is a arithmetic char **/ if ("+-*^/%=;(),><".indexOf(curr_char) >= 0) { this.strBuffer_new = "" + curr_char; this.proc_wordtype = this.WORDTYPE_DELIMITER; this.proc_position++; return; }
/** * check that this char is a quotes char **/ if (curr_char == '"') { int index_start = this.proc_position + 1; do { this.proc_position++; curr_char = this.proc_contents.charAt(this.proc_position); } while (curr_char != '"' && curr_char != '/r' && curr_char != '/n'); if (curr_char == '/r' || curr_char == '/n') { this.showError(1); } int index_end = this.proc_position; this.strBuffer_new = this.proc_contents.substring(index_start, index_end); this.proc_wordtype = this.WORDTYPE_QUOTE; this.proc_position++; return; }
/** * check that this char is a digit char **/ if (Character.isDigit(curr_char)) { int index_start = this.proc_position; while (!this.isDelim(curr_char)) { this.proc_position++; curr_char = this.proc_contents.charAt(this.proc_position); } int index_end = this.proc_position; this.strBuffer_new = this.proc_contents.substring(index_start, index_end); this.proc_wordtype = this.WORDTYPE_NUMBER; return; }
/** * check that this char is a letter char **/ if (Character.isLetter(curr_char)) { int index_start = this.proc_position; while (!this.isDelim(curr_char)) { this.proc_position++; curr_char = this.proc_contents.charAt(this.proc_position); } int index_end = this.proc_position; this.strBuffer_new = this.proc_contents.substring(index_start, index_end); this.proc_wordtype = this.WORDTYPE_STRING;
/** * check this string is a command or variable **/ if (this.lookup(this.strBuffer_new) > 0) { this.proc_wordtype = this.WORDTYPE_COMMAND; } else { this.proc_wordtype = this.WORDTYPE_VARIABLE; } return; } }
// }}} // {{{ int lookup(String strBuffer) /** * * * * **/ private int lookup(String strBuffer) { String str = strBuffer.toLowerCase(); for (int i = 0; i < this.COMMAND_NUM; i++) { if (str.equals(this.command_table[i].name)) { return this.command_table[i].cmdNo; } } return 0; }
// }}} // {{{ boolean isWhite(char c) /** * * * **/ private boolean isWhite(char c) { if (c == ' ' || c == 0x9) { return true; } return false; }
// }}} // {{{ boolean isDelim(char c) /** * * * * **/ private boolean isDelim(char c) { if (c == 0x9 || c == '/r' || c == '/n' || ";,+-<>/*%^=()".indexOf(c) >= 0) { return true; } return false; }
// }}} // {{{ void showError(int type) /** * * * **/ private void showError(int type) { }
// }}}
// {{{ int findVar(String str) /** * * * **/ private int findVar(char ch) { if (!Character.isLetter(ch)) { this.showError(4); return 0; } return Integer.valueOf(Character.toUpperCase(ch) - 'A'); }
// }}}
// {{{ /** * * * * @access private **/ private void assignment() { this.checkCurrChar(); if (!Character.isLetter(this.strBuffer_new.charAt(0))) { this.showError(4); return; } char ch = this.strBuffer_new.charAt(0); int var = Integer.valueOf(Character.toUpperCase(ch) - 'A'); this.checkCurrChar(); if (this.strBuffer_new.charAt(0) != '=') { this.showError(3); return; } int value = 0; value = this.getExp(value); this.variables[var] = value; }
// }}} // }}}}
// }}}