#include <iostream>
#include <string>
#include <memory>
#include <list>
#include <sstream>
#include <map>
#include <fstream>

using namespace std;

class token
{
public:
	virtual bool is_int() {
		return false;
	}
	virtual bool is_plus() {
		return false;
	}
	virtual bool is_star() {
		return false;
	}
	virtual bool is_leftP() {
		return false;
	}
	virtual bool is_rightP() {
		return false;
	}
	virtual int get_int_val() {
		throw - 1;
	}
	virtual bool is_var() {
		return false;
	}
	virtual bool is_semi() {
		return false;
	}
	virtual bool is_echo() {
		return false;
	}
	virtual bool is_equals() {
		return false;
	}
	virtual bool is_read() {
		return false;
	}
	virtual string get_var_name() {
		throw - 1;
	}
};

#define make_token(a) class t_##a : public token { \
	public: bool is_##a() { return true; }};

make_token (echo)
make_token (equals)
make_token (read)
make_token (leftP)
make_token (rightP)
make_token (semi)
make_token (plus)
make_token (star)

class t_var : public token
{
public:
	t_var (const string& name) : name (name) {}

	bool is_var() {
		return true;
	}

	string get_var_name() {
		return name;
	}
private:
	string name;
};

class t_int : public token
{
public:
	t_int (int val) : val (val) {}

	bool is_int() {
		return true;
	}

	int get_int_val() {
		return val;
	}
private:
	int val;

};


using toklist = list<unique_ptr<token>>;
toklist tokenize(istream& in)
{
	toklist t;
	while (in.good() && !in.eof()) {
		string temp;
		in >> temp;
		if (temp == "EOF") break;

#define MATCH_TOKEN(s, l) if(temp == s) { t.push_back(make_unique<l>()); }

		MATCH_TOKEN ("+", t_plus)
		else MATCH_TOKEN ("*", t_star)
		else MATCH_TOKEN ("(", t_leftP)
		else MATCH_TOKEN (")", t_rightP)
		else MATCH_TOKEN ("echo", t_echo)
		else MATCH_TOKEN (";", t_semi)
		else MATCH_TOKEN ("read", t_read)
		else MATCH_TOKEN ("=", t_equals)
		else if (!temp.empty() && temp[0] >= '0'
			&& temp[0] <= '9') {
			int val;
			istringstream (temp) >> val;
			t.push_back (make_unique<t_int> (val));
		} else if (!temp.empty()) {
			t.push_back (make_unique<t_var> (temp));
		}

#undef MATCH_TOKEN

	}

	return t;
}
typedef map<string, int> Scope;
class Expr
{
public:
	virtual int eval (Scope &s) = 0;
};

class Number : public Expr
{
	int val;
public:
	Number (int v) : val (v) {}
	int eval (Scope &s) {
		return val;
	}
};

class Variable : public Expr
{
	string name;
public:
	Variable (const string& n) : name (n) {}
	int eval (Scope &s) {
		return s[name];
	}
	const string& getName() {
		return name;
	}
};

class Plus : public Expr
{
	unique_ptr<Expr> l, r;
public:
	Plus (unique_ptr<Expr> &&l, unique_ptr<Expr> &&r) : l (move (l)), r (move (r)) {};
	int eval (Scope &s) {
		return l->eval (s) + r->eval (s);
	}
};

class Mult : public Expr
{
	unique_ptr<Expr> l, r;
public:
	Mult (unique_ptr<Expr> &&l, unique_ptr<Expr> &&r) : l (move (l)), r (move (r)) {};
	int eval (Scope &s) {
		return l->eval (s) * r->eval (s);
	}
};

class Command
{
public:
	virtual void run (Scope & s) = 0;
};

class CompoundCommand : public Command
{
	unique_ptr<Command> l, r;
public:
	CompoundCommand (unique_ptr<Command> &&l, unique_ptr<Command> &&r) : l (move (l)), r (move (r)) {};
	void run (Scope & s) {
		l->run (s);
		r->run (s);
	}
};

class Assignment : public Command
{
	Variable var;
	unique_ptr<Expr> expr;
public:
	Assignment (const Variable& var, unique_ptr<Expr> &&expr) : var (var), expr (move (expr)) {

	}

	void run (Scope & s) {
		s[var.getName()] = expr->eval (s);

	}
};

class Read : public Command
{
	Variable var;
public:
	Read (const Variable& var) : var (var) {

	}

	void run (Scope & s) {
		cin >> s[var.getName()];
	}
};

class Echo : public Command
{
	unique_ptr<Expr> expr;
public:
	Echo (unique_ptr<Expr> &&expr) : expr (move (expr)) {
	}

	void run (Scope & s) {
		cout << expr->eval (s) << endl;
	}
};

unique_ptr<Expr> parse_expr (toklist &t);

unique_ptr<Expr> parse_baseexpr (toklist& t)
{

	if (!t.empty() && t.front()->is_int()) {
		int val = t.front()->get_int_val();
		t.pop_front();
		return make_unique<Number> (val);
	}
	if (!t.empty() && t.front()->is_leftP()) {
		t.pop_front();
		auto exp = parse_expr (t);
		if (!t.empty() && t.front()->is_rightP()) {
			t.pop_front();
			return exp;
		} else
			throw - 3;
	}
	if (!t.empty() && t.front()->is_var()) {
		string name = t.front()->get_var_name();
		t.pop_front();
		return make_unique<Variable> (name);
	}
	throw - 2;

}
unique_ptr<Expr> parse_multexpr (toklist &t)
{
	unique_ptr<Expr> left = parse_baseexpr (t);
	if (!t.empty() && t.front()->is_star()) {
		t.pop_front();
		return make_unique<Mult> (move (left), parse_multexpr (t));
	} else {
		return left;
	}
}


unique_ptr<Expr> parse_addexpr (toklist &t)
{
	unique_ptr<Expr> left = parse_multexpr (t);
	if (!t.empty() && t.front()->is_plus()) {
		t.pop_front();
		return make_unique<Plus> (move (left), parse_addexpr (t));
	} else {
		return left;
	}
}

unique_ptr<Expr> parse_expr (toklist &t)
{
	return parse_addexpr (t);
}
unique_ptr<Command> parse_statement (toklist &t);

unique_ptr<Command> parse_program (toklist &t)
{
	unique_ptr<Command> left = parse_statement (t);
	if (!t.empty() && t.front()->is_semi()) {
		t.pop_front();
		return make_unique<CompoundCommand> (move (left), parse_program (t));
	} else {
		return left;
	}
}
unique_ptr<Command> parse_statement (toklist &t)
{
	if (!t.empty() && t.front()->is_echo()) {
		t.pop_front();
		return make_unique<Echo> (parse_expr (t));
	}
	if (!t.empty() && t.front()->is_read()) {
		t.pop_front();
		if (!t.empty() && t.front()->is_var()) {
			string name = t.front()->get_var_name();
			t.pop_front();
			return make_unique<Read> (Variable (name));
		} else {
			throw - 42;
		}
	}
	if (!t.empty() && t.front()->is_var()) {
		string name = t.front()->get_var_name();
		t.pop_front();

		if (!t.empty() && t.front()->is_equals()) {

			t.pop_front();
			return make_unique<Assignment> (Variable (name), parse_expr (t));
		}
		throw - 43;
	}
	throw -44;
}


int main(int argc, char ** argv)
{
	string filename;
	if (argc == 2)
		filename = argv[1];
	else {
		cerr << "neumis zadavat argumenty" << endl;
		return(1);
	}
	ifstream in(filename);
	if(!in.good()) {
		cerr << "nelze otevrit" << endl;
		return 2;
	}
	auto t = tokenize(in);
	//for (auto&i : t) cout << typeid(*i).name() << endl;
	auto p = parse_program (t);
	Scope s;
	p->run (s);
	return 0;
}
