import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.regex.*;
class Ideone
{
{
try {
Excutor excutor = new Excutor();
while ((line = in.readLine()) != null) {
try {
List<Token> tokens = Tokenizer.tokenize(line);
if (excutor.doEditorCommand(tokens) < 0) {
break;
}
} catch (SyntaxError er) {
}
}
// System.out.println(excutor);
}
}
}
enum TokenType
{
INT, DBL, STR, NAME, SYMBL, SHARP, SEMICOLON,
OP_BRKT, CL_BRKT, COMMA, COLON,
UNKNOWN}
final class Token
{
final TokenType type;
public Token
(TokenType type,
String token
) {
this.type = type;
this.token = token;
}
public TokenType getType() { return type; }
public String getToken
() { return token
; } @Override
{
return "[" + type + " : " + token + "]";
}
}
class SyntaxError
extends java.
lang.
Exception {
public SyntaxError
(String msg
) { super(msg
); } public SyntaxError
(Throwable ex
) { super(ex
); } public SyntaxError(List<Token> tokens, int index)
{
super("token index(" + index + "): " + tokens.toString());
}
}
final class TokenError extends SyntaxError
{
public TokenError
(String line
) { super(line
); } }
final class Tokenizer
{
private static Pattern p_space = Pattern.compile("^\\s+");
private static Pattern p_int = Pattern.compile("^\\d+");
private static Pattern p_dbl = Pattern.compile("^\\d*\\.\\d+");
private static Pattern p_str = Pattern.compile("^\"(\"\"|[^\"])*\"");
private static Pattern p_name = Pattern.compile("^[A-Za-z][A-Za-z0-9]*\\$?");
private static Pattern p_symbl = Pattern.compile("^(>=|<=|<>|[=<>+\\*/-])");
public static List
<Token
> tokenize
(String line
) throws TokenError
{
List<Token> list = new ArrayList<Token>();
Matcher m = null;
TokenType type = null;
int offset = 0;
while (line.length() > 0) {
if ((m = p_space.matcher(line)).lookingAt()) {
line = line.substring(m.end());
continue;
} else if ((m = p_dbl.matcher(line)).lookingAt()) {
type = TokenType.DBL;
} else if ((m = p_int.matcher(line)).lookingAt()) {
type = TokenType.INT;
} else if ((m = p_str.matcher(line)).lookingAt()) {
type = TokenType.STR;
} else if ((m = p_name.matcher(line)).lookingAt()) {
type = TokenType.NAME;
} else if ((m = p_symbl.matcher(line)).lookingAt()) {
type = TokenType.SYMBL;
} else {
m = null;
offset = 1;
if (line.startsWith(token = "(")) {
type = TokenType.OP_BRKT;
} else if (line.startsWith(token = ")")) {
type = TokenType.CL_BRKT;
} else if (line.startsWith(token = ":")) {
type = TokenType.COLON;
} else if (line.startsWith(token = ",")) {
type = TokenType.COMMA;
} else if (line.startsWith(token = "#")) {
type = TokenType.SHARP;
} else if (line.startsWith(token = ";")) {
type = TokenType.SEMICOLON;
} else {
throw new TokenError(line);
}
}
if (m != null) {
token = m.group();
if (TokenType.NAME.equals(type)) {
token = token.toUpperCase();
}
offset = m.end();
}
list.add(new Token(type, token));
line = line.substring(offset);
}
return list;
}
}
final class ExcuteError extends SyntaxError
{
public ExcuteError
(Throwable ex
) { super(ex
); } public ExcuteError
(String msg
) { super(msg
); } }
class VarArray<T>
{
}
enum ResultType
{
INT, DBL, STR
}
class Result
{
private int offset;
private int intvalue = 0;
private double dblvalue = 0;
private String strvalue
= null; private ResultType type;
public ResultType getType()
{
return type;
}
public int getOffset()
{
return offset;
}
{
if (ResultType.INT.equals(type)) {
} else if (ResultType.DBL.equals(type)) {
return Double.
valueOf(dblvalue
); } else {
return null;
}
}
{
return strvalue;
}
}
final class Excutor
{
private NavigableMap
<Integer, List
<Token
>> program
= new TreeMap
<Integer, List
<Token
>>();
private Map
<String, VarArray
<String
>> strarrs
= new HashMap
<String, VarArray
<String
>>(); private Map
<String, VarArray
<Number
>> numarrs
= new HashMap
<String, VarArray
<Number
>>(); private Map
<String, String
> strvars
= new HashMap
<String, String
>(); private Map
<String, Number
> numvars
= new HashMap
<String, Number
>();
private Integer programcounter
= null; private Deque<Integer> programcounterstack = new ArrayDeque<Integer>();
private int arraybase = 0;
private boolean jumpflag = false;
public Excutor() {}
private void printLine
(Integer linenum, List
<Token
> tokens
) {
System.
out.
printf("%05d ", linenum.
intValue()); TokenType before = null, type;
for (int i = 1; i < tokens.size(); i++) {
Token token = tokens.get(i);
type = token.getType();
if (TokenType.NAME.equals(before)) {
switch (type) {
case NAME:
case INT:
case DBL:
case SHARP:
case STR:
break;
default:
break;
}
}
System.
out.
print(tokens.
get(i
).
getToken()); before = type;
}
}
private Result calc(List<Token> tokens, int index) throws SyntaxError
{
return null;
}
public int doEditorCommand(List<Token> tokens) throws SyntaxError
{
if (tokens == null || tokens.isEmpty()) {
return 0;
}
Token first = tokens.get(0);
String token
= first.
getToken(); TokenType type = first.getType();
if (TokenType.INT.equals(type)) {
if (tmpint.intValue() < 1) {
throw new SyntaxError(token);
}
program.put(tmpint, tokens);
return 0;
} else if (TokenType.NAME.equals(type) == false) {
throw new ExcuteError(token);
}
switch (token) {
case "CONT": // プログラムの再開
case "EXIT": // インタプリタの終了
return -1;
case "LIST": // プログラムの表示
do_list(tokens);
break;
case "LOAD": // プログラムのロード
case "NEW": // プログラムと変数の全消去
case "RENUM": // プログラムの行番号再割り当て
break;
case "RUN": // プログラムの実行
do_run(tokens);
break;
case "SAVE": // プログラムの保存
break;
default:
excute(tokens, 0);
break;
}
return 0;
}
private void do_list(List<Token> tokens) throws SyntaxError
{
Token first, second, third;
Map
<Integer, List
<Token
>> list
= null; try {
switch (tokens.size()) {
case 1:
list = program;
break;
case 2:
first = tokens.get(1);
if (TokenType.INT.equals(first.getType()) == false) {
throw new SyntaxError(tokens ,1);
}
start
= Integer.
valueOf(first.
getToken()); if (start.intValue() < 1) {
throw new SyntaxError(tokens ,1);
}
list = program.tailMap(start);
break;
case 3:
if ("-".equals(tokens.get(1).getToken()) == false) {
throw new SyntaxError(tokens ,1);
}
second = tokens.get(2);
if (TokenType.INT.equals(second.getType()) == false) {
throw new SyntaxError(tokens ,2);
}
end
= Integer.
valueOf(second.
getToken()); if (end.intValue() < 1) {
throw new SyntaxError(tokens ,2);
}
list = program.headMap(end, true);
break;
case 4:
first = tokens.get(1);
if (TokenType.INT.equals(first.getType()) == false) {
throw new SyntaxError(tokens ,1);
}
start
= Integer.
valueOf(first.
getToken()); if (start.intValue() < 1) {
throw new SyntaxError(tokens ,1);
}
if ("-".equals(tokens.get(2).getToken()) == false) {
throw new SyntaxError(tokens ,2);
}
third = tokens.get(3);
if (TokenType.INT.equals(third.getType()) == false) {
throw new SyntaxError(tokens ,3);
}
end
= Integer.
valueOf(third.
getToken()); if (end.intValue() < 1) {
throw new SyntaxError(tokens ,3);
}
list = program.subMap(start, true, end, true);
break;
default:
throw new SyntaxError(tokens, 0);
}
} catch (SyntaxError er) {
throw er;
throw new ExcuteError(ex);
}
if (list == null) {
return;
}
printLine(key, list.get(key));
}
}
private void do_run(List<Token> tokens) throws SyntaxError
{
switch (tokens.size()) {
case 1:
programcounter
= program.
ceilingKey(Integer.
valueOf(1)); if (programcounter == null) {
throw new SyntaxError("Program is not found");
}
break;
case 2:
Token first = tokens.get(1);
if (TokenType.INT.equals(first.getType()) == false) {
throw new SyntaxError("Illegal Argument");
}
programcounter
= Integer.
valueOf(first.
getToken()); if (programcounter.intValue() < 1) {
throw new SyntaxError("Wrong Line Number");
}
if (program.containsKey(programcounter) == false) {
throw new SyntaxError("Not found Line Number");
}
break;
default:
throw new SyntaxError("Illegal Arguments");
}
List<Token> line = null;
try {
while (programcounter != null) {
line = program.get(programcounter);
excute(line, 1);
if (jumpflag == false) {
programcounter = program.higherKey(programcounter);
} else {
jumpflag = false;
}
}
} catch (SyntaxError er) {
throw er;
}
}
private int excute(List<Token> tokens, int index) throws SyntaxError
{
if (index < 0 || index >= tokens.size()) {
return tokens.size();
}
Token first = tokens.get(index);
TokenType type = first.getType();
while (TokenType.COLON.equals(type)) {
index++;
if (index == tokens.size()) {
return index;
}
first = tokens.get(index);
type = first.getType();
}
if (TokenType.NAME.equals(type) == false) {
throw new SyntaxError(first.toString());
}
String cmd
= first.
getToken(); int offset = index;
switch (cmd) {
case "BASE": // 配列の下限(0/1)の設定
offset = cmd_base(tokens, index + 1);
break;
case "BREAK": // FORループの脱出
case "DATA": // データの列挙
case "DIM": // 配列変数の宣言
case "ELSE": // IF文のELSE節の開始
case "END": // プログラムの終了
case "FILE": // ファイルの割り当て
case "FOR": // 繰り返し
break;
case "GO": // GOTOの分割トークン
if (index + 2 >= tokens.size()) {
throw new SyntaxError(tokens, index);
}
if ("TO".equals(tokens.get(index + 1).getToken()) == false) {
throw new SyntaxError(tokens, index);
}
offset = cmd_goto(tokens, index + 2);
break;
case "GOTO": // ジャンプ
offset = cmd_goto(tokens, index + 1);
break;
case "GOSUB": // サブルーチンジャンプ
offset = cmd_gosub(tokens, index + 1);
break;
case "IF": // 条件節
case "INPUT": // キーボードからの値の入力
break;
case "LET": // 変数への代入
offset = cmd_let(tokens, index + 1);
break;
case "NEXT": // FOR文の末端
case "PRINT": // 画面へ値を出力
break;
case "REM": // コメント行
offset = tokens.size();
break;
case "RESTORE": // データ・ファイルの読み込み位置のリセット
break;
case "RETURN": // サブルーチンからの脱出
offset = cmd_return(tokens, index);
break;
case "STOP": // プログラムの中断
break;
default:
offset = cmd_let(tokens, index);
break;
}
return offset;
}
@Override
{
return program.toString().replaceAll("(\\d+=\\[\\[)", "\n$1");
}
private int cmd_goto(List<Token> tokens, int index) throws SyntaxError
{
if (index >= tokens.size()) {
throw new SyntaxError(tokens, index);
}
if (index + 1 < tokens.size()) {
if (TokenType.COLON.equals(tokens.get(index + 1).getType()) == false) {
throw new SyntaxError(tokens, index + 1);
}
}
Token first = tokens.get(index);
if (TokenType.INT.equals(first.getType()) == false) {
throw new SyntaxError(tokens, index);
}
if (program.containsKey(next) == false) {
throw new SyntaxError(tokens, index);
}
programcounter = next;
jumpflag = true;
return tokens.size();
}
private int cmd_gosub(List<Token> tokens, int index) throws SyntaxError
{
if (index >= tokens.size()) {
throw new SyntaxError(tokens, index);
}
if (index + 1 < tokens.size()) {
if (TokenType.COLON.equals(tokens.get(index + 1).getType()) == false) {
throw new SyntaxError(tokens, index + 1);
}
}
Token first = tokens.get(index);
if (TokenType.INT.equals(first.getType()) == false) {
throw new SyntaxError(tokens, index);
}
if (program.containsKey(next) == false) {
throw new SyntaxError(tokens, index);
}
try {
programcounterstack.push(programcounter);
programcounter = next;
jumpflag = true;
return tokens.size();
throw new ExcuteError(ex);
}
}
private int cmd_return(List<Token> tokens, int index) throws SyntaxError
{
if (index < tokens.size()) {
if (TokenType.COLON.equals(tokens.get(index).getType()) == false) {
throw new SyntaxError(tokens, index);
}
}
try {
Integer back
= programcounterstack.
pop(); programcounter = program.higherKey(back);
jumpflag = true;
return tokens.size();
throw new ExcuteError(ex);
}
}
private int cmd_base(List<Token> tokens, int index) throws SyntaxError
{
try {
Token first = tokens.get(index);
if (TokenType.INT.equals(first.getType()) == false) {
throw new SyntaxError(tokens, index);
}
int tmpint
= Integer.
parseInt(first.
getToken()); if (tmpint != 0 && tmpint != 1) {
throw new SyntaxError(tokens, index + 1);
}
arraybase = tmpint;
return excute(tokens, index + 1);
} catch (SyntaxError er) {
throw er;
throw new ExcuteError(ex);
}
}
private int cmd_let(List<Token> tokens, int index) throws SyntaxError
{
try {
Token first = tokens.get(index);
String name
= first.
getToken(); // if (checkKeyword(name)) // 予約語チェック
// throw new SyntaxError("Wrong variable name: " + name);
index++;
if (name.lastIndexOf("$") > 0) {
if (strarrs.containsKey(name)) {
if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
throw new SyntaxError(tokens, index);
}
} else {
if ("=".equals(tokens.get(index).getToken()) == false) {
throw new SyntaxError(tokens, index);
}
index++;
// Result result = calc(tokens, index);
// if (result.getType() != "STRING")
// throw new ExcuteError();
// offset = result.getOffset();
// strvars.put(name, result.getStrValue());
}
} else {
if (numarrs.containsKey(name)) {
if (TokenType.OP_BRKT.equals(tokens.get(index).getType()) == false) {
throw new SyntaxError(tokens, index);
}
} else {
if ("=".equals(tokens.get(index).getToken()) == false) {
throw new SyntaxError(tokens ,index);
}
// Result result = calc(tokens, index);
// if (result.getType() != "NUMBER")
// throw new ExcuteError();
// offset = result.getOffset();
// numvars.put(name, result.getNumValue());
}
}
// return excute(tokens, index);
return tokens.size();
} catch (SyntaxError er) {
throw er;
ex.printStackTrace();
throw new ExcuteError(tokens.toString());
}
}
}