#include<iostream>
#include<fstream>
#include<sstream>
#include<vector>
#include<string>
#include<map>
#include<stack>
using namespace std;
vector<int> zas; // zasobnik
int linenumber; // pointer na #radku v kodu
map<string,int> lab; // navesti: jmeno -> #radku
map<string,int> functions; // jmeno fce -> #radku
stack<int> fzas; // zasobnik volani fci
class instr {
public:
virtual void Execute() = 0;
};
class add : public instr {
void Execute() {
int b = zas.back(); zas.pop_back();
int a = zas.back(); zas.pop_back();
zas.push_back(a+b);
}
};
class sub : public instr {
void Execute() {
int b = zas.back(); zas.pop_back();
int a = zas.back(); zas.pop_back();
zas.push_back(a-b);
}
};
class mul : public instr {
void Execute() {
int b = zas.back(); zas.pop_back();
int a = zas.back(); zas.pop_back();
zas.push_back(a*b);
}
};
class div2 : public instr {
void Execute() {
int b = zas.back(); zas.pop_back();
int a = zas.back(); zas.pop_back();
zas.push_back(a+b);
}
};
class mod : public instr {
void Execute() {
int b = zas.back(); zas.pop_back();
int a = zas.back(); zas.pop_back();
zas.push_back(a%b);
}
};
class read : public instr {
public:
void Execute() {
int x;
cin >> x;
zas.push_back(x);
}
};
class go2 : public instr {
string nazev;
public:
go2(string navesti) : nazev(navesti) {}
void Execute() {
linenumber = lab[nazev] - 1;
}
};
class jz : public instr {
string nazev;
public:
jz(string navesti) : nazev(navesti) {}
void Execute() {
int x = zas.back(); zas.pop_back();
if (x == 0) {
linenumber = lab[nazev] - 1;
}
}
};
class call : public instr {
string nazev;
public:
call(string navesti) : nazev(navesti) {}
void Execute() {
fzas.push(linenumber);
linenumber = functions[nazev];
}
};
class ret : public instr {
public:
ret() {}
void Execute() {
if (!fzas.empty()) {
linenumber = fzas.top(); fzas.pop();
}
}
};
class dup : public instr {
int n;
public:
dup(int n_) : n(n_) {}
void Execute() {
zas.push_back(zas[zas.size()-1+n]);
}
};
class push : public instr {
int n;
public:
push(int n_) : n(n_) {}
void Execute() {
zas.push_back(n);
}
};
class pop : public instr {
public:
pop() {}
void Execute() {
int x = zas.back();
zas.pop_back();
//cout << "popped " << x << endl;
}
};
class print : public instr {
public:
void Execute() {
int x = zas.back(); zas.pop_back();
cout << x << endl;
//system("pause");
}
};
class blop : public instr {
public:
void Execute() {}
};
int main() {
fstream infile;
infile.open("sum.txt", ios::in);
// parse
linenumber = 0;
int mainln = -1;
vector<instr *> prog; // seznam instrukci programu
string cur_fun("");
do {
string line, nazev, ins;
getline(infile, line);
// navesti
bool isLab = false;
for (int i=0; i<line.size(); i++) {
if (line[i] == ':') {
stringstream ss(line);
ss >> nazev >> ins;
nazev.erase(nazev.size()-1, 1);
isLab = true;
lab.insert(make_pair(nazev+cur_fun, linenumber));
}
}
if (!isLab) {
ins = line;
}
// jednoslovne prikazy
if (!ins.compare("read")) {
prog.push_back(new read());
} else if (!ins.compare("print")) {
prog.push_back(new print());
} else if (!ins.compare("add")) {
prog.push_back(new add());
} else if (!ins.compare("sub")) {
prog.push_back(new sub());
} else if (!ins.compare("mul")) {
prog.push_back(new mul());
} else if (!ins.compare("div")) {
prog.push_back(new div2());
} else if (!ins.compare("mod")) {
prog.push_back(new mod());
} else if (!ins.compare("pop")) {
prog.push_back(new pop());
} else if (!ins.compare("return")) {
prog.push_back(new ret());
// viceslovne prikazy
} else {
stringstream ss(ins);
ss >> ins >> nazev;
if (!ins.compare("goto")) {
prog.push_back(new go2(nazev+cur_fun));
} else if (!ins.compare("jz")) {
prog.push_back(new jz(nazev+cur_fun));
} else if (!ins.compare("push")) {
stringstream ss2(nazev);
int n;
ss2 >> n;
prog.push_back(new push(n));
} else if (!ins.compare("dup")) {
stringstream ss2(line);
int n;
ss2 >> nazev;
if (isLab) {
ss2 >> nazev;
}
ss2 >> n;
prog.push_back(new dup(n));
} else if (!ins.compare("function")) {
stringstream ss2(line);
ss2 >> nazev >> nazev;
functions.insert(make_pair(nazev, linenumber));
if (!nazev.compare("main")) {mainln = linenumber;}
cur_fun = nazev;
prog.push_back(new blop());
} else if (!ins.compare("call")) {
stringstream ss2(line);
ss2 >> nazev;
if (isLab) {
ss2 >> nazev;
}
ss2 >> nazev;
prog.push_back(new call(nazev));
} else {
prog.push_back(new blop()); // prazdny radek
}
}
linenumber++;
} while (!infile.eof());
// execution
for (linenumber= (mainln<0) ? 0 : mainln; linenumber<prog.size(); linenumber++) {
prog[linenumber]->Execute();
}
system("pause");
return 0;
}