/*
 * Version 2: 2 February 2008
 */

import java.util.*;
import java.io.*;

public class Simulator {

	static int HEAP_SIZE = 100000;
	static int[] heap = new int[HEAP_SIZE];
	static int hp = 0;

	static int STACK_SIZE = 1000;
	static int[] stack;
	static int sp;

	static int r1, r2;

	static ArrayList<String[]> code = new ArrayList<String[]>();

	static Map<String, Integer> labelLocation = new HashMap<String, Integer>(),
			functionLocation = new HashMap<String, Integer>();

	public static void main(String[] args) {
		try {
			Scanner reader;
			if (args.length > 0) {
				String fileName = args[0];
				reader = new Scanner(new File(fileName));
			} else
				reader = new Scanner(System.in);
			while (reader.hasNextLine()) {
				String[] nextLineTokens = reader.nextLine().trim().split(" |\t");
				code.add(nextLineTokens);
				if (nextLineTokens.length < 2)
					continue;

				if (nextLineTokens[0].equals("FUNCTION")) {
					if (functionLocation.containsKey(nextLineTokens[1]))
						throw new SimulatorException("Duplicate function label "
								+ nextLineTokens[1]);
					functionLocation.put(nextLineTokens[1], code.size() - 1);
				}
				if (nextLineTokens[0].equals("LABEL")) {
					if (labelLocation.containsKey(nextLineTokens[1]))
						throw new SimulatorException("Duplicate label "
								+ nextLineTokens[1]);
					labelLocation.put(nextLineTokens[1], code.size() - 1);
				}
			}
			System.out.println("SIMULATION STARTS\n");
			call("main", new ArrayList<Integer>());
		} catch (SimulatorException e) {
			System.err.println("Simulator error at line " + e.line + ": "
					+ e.message);
			e.printStackTrace();
			System.exit(1);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}

	static int call(String name, ArrayList<Integer> parameters)
			throws SimulatorException {
		Integer location = functionLocation.get(name);
		if (location == null)
			throw new SimulatorException("Function " + name + " not found!");

		int[] oldStack = stack;
		int oldR1 = r1;
		int oldR2 = r2;
		stack = new int[STACK_SIZE];
		int oldSp = sp;
		sp = 0;
		for (Integer param : parameters)
			stack[sp++] = param.intValue();

		int result;
		ArrayList<Integer> possibleNextParameters = new ArrayList<Integer>();

		for (int pc = location + 1;; pc++) {
			try {
				String[] ins = code.get(pc);
				if (ins.length == 0)
					continue;
				if (ins[0].equals(""))
					continue;

				// System.err.println("At line " + pc );
				// System.err.println("instruction : " + ins[0]);

				/*
				 * PRINT r-val
				 * ERROR message
				 *
				 * MOV l-val r-val
				 * AND l-val r-val1 r-val2
				 * LES l-val r-val1 r-val2
				 * ADD l-val r-val1 r-val2
				 * SUB l-val r-val1 r-val2
				 * MUL l-val r-val1 r-val2
				 * NOT l-val r-val
				 * EQU l-val r-val1 r-val2
				 *
				 * LABEL label
				 * JUMP label
				 * IF r-val label1 label2
				 *
				 * PARAM r-val
				 * CALL l-val name count
				 *
				 * FUNCTION name
				 * RETURN r-val
				 *
				 * PUSH r-val
				 *
				 * ALLOCATE l-val r-val
				 *
				 * HALT
				 */

				if (ins[0].equals("PRINT")) {
					System.out.println(get(ins[1]));
				} else if (ins[0].equals("ERROR")) {
					System.out.println(ins[1]);
					System.out.println("\nSIMULATION FINISHES SUCCESSFULLY");
					System.exit(0);
				} else if (ins[0].equals("MOV")) {
					put(ins[1], get(ins[2]));
				} else if (ins[0].equals("AND")) {
					put(ins[1], toInt(toBoolean(get(ins[2]))
							&& toBoolean(get(ins[3]))));
				} else if (ins[0].equals("LES")) {
					put(ins[1], toInt((get(ins[2])) < (get(ins[3]))));
				} else if (ins[0].equals("ADD")) {
					put(ins[1], ((get(ins[2])) + (get(ins[3]))));
				} else if (ins[0].equals("SUB")) {
					put(ins[1], ((get(ins[2])) - (get(ins[3]))));
				} else if (ins[0].equals("MUL")) {
					put(ins[1], ((get(ins[2])) * (get(ins[3]))));
				} else if (ins[0].equals("NOT")) {
					put(ins[1], toInt(!toBoolean(get(ins[2]))));
				} else if (ins[0].equals("EQU")) {
					put(ins[1], toInt((get(ins[2])) == (get(ins[3]))));
				} else if (ins[0].equals("LABEL")) {
					continue;
				} else if (ins[0].equals("JUMP")) {
					String label = ins[1];
					if (!labelLocation.containsKey(label))
						throw new Exception("Cannot find label: " + label);
					pc = labelLocation.get(label);
				} else if (ins[0].equals("IF")) {
					String label;
					if (toBoolean(get(ins[1])))
						label = ins[2];
					else
						label = ins[3];
					if (!labelLocation.containsKey(label))
						throw new Exception("Cannot find label: " + label);
					pc = labelLocation.get(label);
				} else if (ins[0].equals("PARAM")) {
					possibleNextParameters.add(get(ins[1]));
				} else if (ins[0].equals("CALL")) {
					// CALL l-val name count
					int count = parsePositive(ins[3]);
					ArrayList<Integer> actualNextParameters = new ArrayList<Integer>(
							possibleNextParameters.subList(
									possibleNextParameters.size() - count,
									possibleNextParameters.size()));
					for (int i = 0; i < count; i++)
						possibleNextParameters.remove(possibleNextParameters
								.size() - 1);
					put(ins[1], call(ins[2], actualNextParameters));
				} else if (ins[0].equals("FUNCTION"))
					throw new Exception("Encountered a new function label: "
							+ ins[1] + " when executing another function!");
				else if (ins[0].equals("RETURN")) {
					result = get(ins[1]);
					break;
				} else if (ins[0].equals("PUSH")) {
					stack[sp] = get(ins[1]);
					sp = sp + 1;
				} else if (ins[0].equals("ALLOCATE")) {
					put(ins[1], hp);
					hp += get(ins[2]);
				} else if (ins[0].equals("HALT")) {
					System.out.println("\nSIMULATION FINISHES SUCCESSFULLY");
					System.exit(0);
				} else
					throw new Exception("Invalid instruction: " + ins[0]);
			} catch (SimulatorException e) {
				throw e;
			} catch (Exception e) {
				throw new SimulatorException(e.getMessage(), pc);
			}
		}

		stack = oldStack;
		sp = oldSp;
		r1 = oldR1;
		r2 = oldR2;
		return result;

	}

	/*
	 * l-val ::= HEAP+atom | STACK+offset | register
	 * r-val ::= HEAP+atom | STACK+offset | atom
	 * atom ::= register | POP | int_val | TRUE | FALSE
	 * register ::= R1 | R2
	 */
	static int get(String rVal) throws Exception {
		if (!rVal.contains("@"))
			return getAtom(rVal);
		String[] tokens = rVal.split("@");
		if (tokens[0].equals("HEAP"))
			return heap[getAtom(tokens[1])];
		if (tokens[0].equals("STACK"))
			return stack[parsePositive(tokens[1])];
		throw new Exception("Invalid r-value: " + rVal);
	}

	static int getAtom(String rVal) throws Exception{
		if (rVal.equals("TRUE"))
			return toInt(true);
		if (rVal.equals("FALSE"))
			return toInt(false);
		if (rVal.equals("POP")) {
			sp = sp - 1;
			return stack[sp];
		}
		if (rVal.equals("R1"))
			return r1;
		if (rVal.equals("R2"))
			return r2;
		return parsePositive(rVal);
	}

	static void put(String lVal, int rVal) throws Exception {
		if (lVal.equals("R1")) {
			r1 = rVal;
			return;
		}
		if (lVal.equals("R2")) {
			r2 = rVal;
			return;
		}
		String[] tokens = lVal.split("@");

		if (tokens[0].equals("HEAP")) {
			heap[getAtom(tokens[1])] = rVal;
		}
		else if (tokens[0].equals("STACK"))
			stack[parsePositive(tokens[1])] = rVal;
		else
			throw new Exception("Invalid l-value: " + lVal);
	}

	static boolean toBoolean(int s) throws Exception {
		if (s == 1)
			return true;
		if (s == 0)
			return false;
		throw new Exception("Trying to cast a non-boolean into boolean!");
	}

	static int toInt(boolean b) {
		return b ? 1 : 0;
	}

	static int parsePositive(String s) throws Exception {
		int result = Integer.parseInt(s);
		if (result < 0)
			throw new Exception("Cannot accept negative value here");
		return result;
	}
}

class SimulatorException extends Exception {
	public int line;

	public String message;

	SimulatorException(String message) {
		line = 0;
		this.message = message;
	}

	SimulatorException(String message, int line) {
		this.message = message;
		this.line = line;
	}

	public String getMessage() {
		return message;
	}

}

