#include <cassert>
#include <iostream>
#include <stack>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
// super class of all operations
class Op {
protected:
Op() = default;
public:
virtual ~Op() = default;
virtual void exec() const = 0;
// disabled: (to prevent accidental usage)
Op(const Op&) = delete;
Op& operator=(const Op&) = delete;
};
// super class of grouping operations
class Grp: public Op {
protected:
vector<Op*> _pOps; // nested operations
protected:
Grp() = default;
virtual ~Grp()
{
for (Op *pOp : _pOps) delete pOp;
}
public:
void add(Op *pOp) { _pOps.push_back(pOp); }
// disabled: (to prevent accidental usage)
Grp(const Grp&) = delete;
Grp& operator=(const Grp&) = delete;
};
// class for repeat op.
class RP: public Grp {
private:
unsigned _n; // repeat count
public:
RP(unsigned n): Grp(), _n(n) { }
virtual ~RP() = default;
virtual void exec() const
{
cout << "Exec. RP" << _n << endl;
for (unsigned i = 0; i < _n; ++i) {
for (const Op *pOp : _pOps) pOp->exec();
}
}
// disabled: (to prevent accidental usage)
RP(const RP&) = delete;
RP& operator=(const RP&) = delete;
};
// class for TP op.
class TP: public Op {
public:
TP() = default;
virtual ~TP() = default;
virtual void exec() const
{
cout << "Exec. TP" << endl;
}
};
// class for TT op.
class TT: public Op {
public:
TT() = default;
virtual ~TT() = default;
virtual void exec() const
{
cout << "Exec. TT" << endl;
}
};
// class for MD sequence
class MD: public Grp {
private:
unsigned _axis;
public:
MD(unsigned axis): Grp(), _axis(axis) { }
virtual ~MD() = default;
virtual void exec() const
{
cout << "Exec. MD" << _axis << endl;
for (const Op *pOp : _pOps) pOp->exec();
}
};
typedef unsigned char uchar;
enum Token {
TkMD = 'M' | 'D' << 8,
TkRP = 'R' | 'P' << 8,
TkTP = 'T' | 'P' << 8,
TkTT = 'T' | 'T' << 8
};
inline Token tokenize(uchar c0, uchar c1) { return (Token)(c0 | c1 << 8); }
MD* compile(istream &in)
{
MD *pMD = nullptr;
stack<Op*> pOpsNested;
#define ERROR \
delete pMD; \
while (pOpsNested.size()) { delete pOpsNested.top(); pOpsNested.pop(); } \
return nullptr
for (;;) {
// read command (2 chars)
char cmd[2];
if (in >> cmd[0] >> cmd[1]) {
//cout << "DEBUG: token: " << hex << tokenize(cmd[0], cmd[1]) << dec << endl;
switch (tokenize(cmd[0], cmd[1])) {
case TkMD: { // MD<num>
int num;
if (in >> num) {
if (pMD) {
cerr << "ERROR: Unexpected command 'MD" << num << "'!" << endl;
ERROR;
}
pMD = new MD(num);
} else {
cerr << "ERROR: Number expected after 'MD'!" << endl;
ERROR;
}
} break;
case TkRP: { // RP<num>
int num;
if (in >> num) {
if (!pMD) {
cerr << "ERROR: Unexpected command 'RP" << num << "'!" << endl;
ERROR;
}
RP *pRP = new RP(num);
while (pOpsNested.size()) {
pRP->add(pOpsNested.top());
pOpsNested.pop();
}
pOpsNested.push(pRP);
} else {
cerr << "ERROR: Number expected after 'MD'!" << endl;
ERROR;
}
} break;
case TkTP: { // TP
if (!pMD) {
cerr << "ERROR: Unexpected command 'TP'!" << endl;
ERROR;
}
pOpsNested.push(new TP());
} break;
case TkTT: { // TT
if (pOpsNested.empty()) {
cerr << "ERROR: Unexpected command 'TT'!" << endl;
ERROR;
}
pOpsNested.push(new TT());
} break;
default:
cerr << "ERROR: Wrong command '" << cmd[0] << cmd[1] << "'!" << endl;
ERROR;
}
} else {
cerr << "ERROR: Command expected!" << endl;
ERROR;
}
// try to read separator
char sep;
if (!(in >> sep)) break; // probably EOF (further checks possible)
if (sep != ',') {
cerr << "ERROR: ',' expected!" << endl;
ERROR;
}
}
#undef ERROR
assert(pMD != nullptr);
while (pOpsNested.size()) {
pMD->add(pOpsNested.top());
pOpsNested.pop();
}
return pMD;
}
int main()
{
// test string
string sample("MD1,TP,RP3,TT,RP2");
// read test string
istringstream in(sample);
MD *pMD = compile(in);
if (!pMD) {
cerr << "Interpreting aborted!" << endl;
return 1;
}
// execute sequence
pMD->exec();
delete pMD;
// done
return 0;
}