package z1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Program implements Runnable {
final String operator = "[<>][>=]?";
final String operation = "[-+*/]";
final String variable = "\\w*[a-zA-Z]\\w*";
final String value = "\\w+";
final String letExp = "^let "+variable+" = "+value+" "+operation+" "+value+"$";
protected Map<String, Command> labels;
protected Map<String, Integer> vars;
protected List<Command> commands;
protected BufferedReader in;
abstract class Command {
protected Command next;
protected int nextLine;
public Command go() {
job();
return next();
}
protected void job() {
//Do nothing
}
protected Command next() {
return next;
}
public void translateJump() throws Exception {
try {
next = commands.get(nextLine);
} catch (IndexOutOfBoundsException e) {
next = null;
}
}
}
class EmptyCommand extends Command {
public EmptyCommand(int nl) {
nextLine = nl;
}
}
class PrintCommand extends Command {
String value;
public PrintCommand(String v, int nl) {
value = v;
nextLine = nl;
}
@Override
public void job() {
println(getValueOf(value));
}
}
class ReadCommand extends Command {
String var;
public ReadCommand(String v, int nl) {
var = v;
nextLine = nl;
}
@Override
protected void job() {
try {
vars.put(var, Integer.parseInt(in.readLine()));
} catch (IOException e) {
System.err.println("Systemova chyba");
System.exit(0);
}
}
}
class LabelCommand extends Command {
String label;
public LabelCommand(String l, int nl) throws Exception {
label = l;
nextLine = nl;
addLabel(label, this);
}
}
class GotoCommand extends Command {
String label;
public GotoCommand(String g) {
label = g;
}
@Override
public void translateJump() throws Exception {
next = labels.get(label);
if (next == null) throw new Exception("Neznamy label");
}
}
class SetCommand extends Command {
String var;
String value;
public SetCommand(String va, String val, int nl) {
nextLine = nl;
value = val;
var = va;
}
@Override
protected void job() {
vars.put(var, getValueOf(value));
}
}
class LetCommand extends Command {
String var;
String value1;
String value2;
char op;
public LetCommand(String v, String val1, String val2, char o, int nl) {
var = v;
value1 = val1;
value2 = val2;
op = o;
nextLine = nl;
}
@Override
protected void job() {
int result = 0;
switch (op) {
case '+':
result = getValueOf(value1) + getValueOf(value2);
break;
case '-':
result = getValueOf(value1) - getValueOf(value2);
break;
case '*':
result = getValueOf(value1) * getValueOf(value2);
break;
case '/':
result = getValueOf(value1) / getValueOf(value2);
break;
}
vars.put(var, result);
}
}
class IfCommand extends Command {
Command then;
char op;
String value1;
String value2;
public IfCommand(String val1, String val2, String o, String restOfLine, int nl) throws Exception {
if (o.equals("<")) {
op = '<';
} else if (o.equals(">")) {
op = '>';
} else if (o.equals(">=")) {
op = ']';
} else if (o.equals("<=")) {
op = '[';
} else if (o.equals("<>")) {
op = '!';
}
value1 = val1;
value2 = val2;
then = parseLine(restOfLine, nl);
nextLine = nl;
}
@Override
public Command go() {
boolean cond = false;
switch (op) {
case '<':
cond = getValueOf(value1) < getValueOf(value2);
break;
case '>':
cond = getValueOf(value1) > getValueOf(value2);
break;
case '[':
cond = getValueOf(value1) <= getValueOf(value2);
break;
case ']':
cond = getValueOf(value1) >= getValueOf(value2);
break;
case '!':
cond = getValueOf(value1) != getValueOf(value2);
break;
}
if (cond) {
return then;
} else {
return next();
}
}
@Override
public void translateJump() throws Exception {
super.translateJump();
then.translateJump();
}
}
protected int getValueOf(String var) {
if (checkNum(var)) return Integer.parseInt(var);
if (!vars.containsKey(var)) vars.put(var, 0);
return vars.get(var);
}
public void addLabel(String label, Command labelCommand) throws Exception {
if (labels.get(label)!=null) {
throw new Exception();
}
labels.put(label, labelCommand);
}
public Program(BufferedReader reader) throws Exception {
commands = new ArrayList<Command>();
vars = new HashMap<String, Integer>();
labels = new HashMap<String, Command>();
in = new BufferedReader(new InputStreamReader(System.in));
String line;
int num = 0;
while ((line = reader.readLine()) != null) {
commands.add(parseLine(line, num++));
}
translateJumps();
}
protected void translateJumps() throws Exception {
for (Command c:commands) {
c.translateJump();
}
}
public void println(Integer integer) {
System.out.println(integer);
}
protected Command parseLine(String line, int num) throws Exception {
Command ret = null;
if (line.equals("") || line.matches("^#.*")) {
ret = new EmptyCommand(num+1);
} else if (line.matches("^println .*")) {
String var = line.substring(8); //za println
if (!checkValue(var)) {
throw new Exception("Chyba v prikazu: "+ line);
}
ret = new PrintCommand(var, num+1);
} else if (line.matches("^readln .*")) {
String var = line.substring(7);
if (!checkVar(var)) {
throw new Exception("Chyba v prikazu: " + line);
}
ret = new ReadCommand(var, num+1);
} else if (line.matches("^goto .*")) {
String label = line.substring(5);
ret = new GotoCommand(label);
} else if (line.matches("^set "+ variable + " = " + value +"$")) {
int pos = line.indexOf('=');
String var = line.substring(4, pos - 1);
String value = line.substring(pos + 2);
ret = new SetCommand(var, value,num+1);
} else if (line.matches(letExp)) {
int pos = line.indexOf('=');
char op = '+';
if (line.indexOf('+') >= 0) {op = '+';}
if (line.indexOf('-') >= 0) {op = '-';}
if (line.indexOf('*') >= 0) {op = '*';}
if (line.indexOf('/') >= 0) {op = '/';}
int opPos = line.indexOf(op);
String var = line.substring(4, pos - 1);
String value1 = line.substring(pos + 2, opPos - 1);
String value2 = line.substring(opPos + 2);
/*Pattern pat = Pattern.compile(letExp);
Matcher mat = pat.matcher(line);*/
ret = new LetCommand(var, value1, value2, op, num+1);
} else if (line.matches("^if "+ value + " " + operator + " " + value + ", " + ".*$")) {
String op = null;
if (line.indexOf("<") >= 0) {op = "<";}
if (line.indexOf(">") >= 0) {op = ">";}
if (line.indexOf("<=") >= 0) {op = "<=";}
if (line.indexOf(">=") >= 0) {op = ">=";}
if (line.indexOf("<>") >= 0) {op = "<>";}
if (op == null) {
throw new Exception("Spatny operator: " + line);
}
int opPos = line.indexOf(op);
int thenPos = line.indexOf(',');
if (thenPos < 0) {
throw new Exception("Chybi prikaz pri splneni podminky:" + line);
}
String value1 = line.substring(3, opPos-1);
String value2 = line.substring(opPos + op.length()+1, thenPos);
String rest = line.substring(thenPos+2);
ret = new IfCommand(value1, value2, op, rest, num+1);
} else if (false) {
} else if (false) {
} else if (false) {
} else if (line.matches(".*:$")) {
String label = line.substring(0, line.length()-1);
ret = new LabelCommand(label, num+1);
} else {
throw new Exception("Neznamy prikaz:" + line);
}
return ret;
}
protected boolean checkValue(String value) {
try {
Integer.parseInt(value);
return true;
} catch (NumberFormatException e) {
return value.matches("^\\w+$");
}
}
protected boolean checkVar(String var) {
return var.matches("^\\w*[a-zA-Z]\\w*$");
}
protected boolean checkNum(String s) {
try {
Integer.parseInt(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public void run() {
Command next;
try {
next = commands.get(0);
} catch (IndexOutOfBoundsException e) {
next = null;
}
while (next != null) {
next = next.go();
}
}
}