#include <iostream>
#include <string>

using namespace std;

class IdentifierNode;
class LiteralNode;
class OperNode;
class AssignmentNode;

class Visitor {
public:
        Visitor() { }
        virtual ~Visitor() { }
 
        virtual void visit(IdentifierNode &) = 0;
        virtual void visit(LiteralNode &) = 0;
        virtual void visit(OperNode &) = 0;
        virtual void visit(AssignmentNode &) = 0;
};

class ASTNode
{
public:
    ASTNode()
    {
        leftChild = 0;
        rightChild = 0;
    }
    virtual void accept(Visitor &) = 0;
    ASTNode *getLeft() {return leftChild;}
    ASTNode *getRight() {return rightChild;}
    void setLeft(ASTNode *node) {leftChild = node;}
    void setRight(ASTNode *node) {rightChild = node;}
private:
    ASTNode *leftChild;
    ASTNode *rightChild;
};

class IdentifierNode : public ASTNode
{
public:
    IdentifierNode(string n) : ASTNode() {name = n;}
    virtual void accept(Visitor & visitor)
    {
        visitor.visit(*this);
        if (this->getLeft())
            this->getLeft()->accept(visitor);
        if (getRight())
            this->getRight()->accept(visitor);
    }
    string getIdentifier() {return name;}
private:
    string name;
};

class LiteralNode : public ASTNode
{
public:
    LiteralNode(int n) : ASTNode() {number = n;}
    virtual void accept(Visitor & visitor)
    {
        visitor.visit(*this);
        if (this->getLeft())
            this->getLeft()->accept(visitor);
        if (getRight())
            this->getRight()->accept(visitor);
    }
    int getLiteral() {return number;}
private:
    int number;
};

class OperNode : public ASTNode
{
public:
    OperNode(char op) : ASTNode() {oper = op;}
    virtual void accept(Visitor & visitor)
    {
        visitor.visit(*this);
        if (this->getLeft())
            this->getLeft()->accept(visitor);
        if (getRight())
            this->getRight()->accept(visitor);
    }
    char getOperator() {return oper;}
private:
    char oper;
};

class AssignmentNode : public ASTNode
{
public:
    AssignmentNode() : ASTNode() {}
    virtual void accept(Visitor & visitor)
    {
        visitor.visit(*this);
        if (this->getLeft())
            this->getLeft()->accept(visitor);
        if (getRight())
            this->getRight()->accept(visitor);
    }
};

class PrintVisitor : public Visitor {
public:
        PrintVisitor() : Visitor() { }
        virtual ~PrintVisitor() { }
 
        virtual void visit(IdentifierNode &node) {
                
                cout << node.getIdentifier() << " ";
        }
        virtual void visit(LiteralNode &node) {
                cout << node.getLiteral() << " ";
        }
        virtual void visit(OperNode &node) {
                cout << node.getOperator() << " ";
        }
        virtual void visit(AssignmentNode &node) {
                cout << ":= ";
        }
};

void ConstructAST(ASTNode *&root)
{
    root = new AssignmentNode();
    ASTNode *temp = root;
    temp->setLeft(new IdentifierNode("dummy"));
    temp->setRight(new OperNode('*'));
    
    temp = temp->getRight();
    temp->setLeft(new OperNode('/'));
    temp->setRight(new LiteralNode(7));

    temp = temp->getLeft();

    temp->setLeft(new OperNode('+'));
    temp->setRight(new OperNode('-'));
    ASTNode *tempLeft = temp->getLeft();
    ASTNode *tempRight = temp->getRight();

    tempLeft->setLeft(new LiteralNode(5));
    tempLeft->setRight(new LiteralNode(3));
    tempRight->setLeft(new LiteralNode(2));
    tempRight->setRight(new LiteralNode(1));
}

int main()
{
    ASTNode *root = 0;
    ConstructAST(root);
    PrintVisitor visitor;
    if(root)
        root->accept(visitor);
    return 0;
}
