// Author: lukyj
#include <iostream>
#include <string>
#include <stack>
#include <sstream>
#include <memory>
class TreeNode;
class TreeNodeConstant;
class TreeNodeVar;
class TreeNodePlus;
class TreeNodeMinus;
class TreeNodeTimes;
using TreeNodePtr = std::unique_ptr<TreeNode>;
class TreeNode {
public:
TreeNode(TreeNodePtr left, TreeNodePtr right) : left_(std::move(left)), right_(std::move(right)) {}
virtual TreeNodePtr derivate() const = 0;
virtual TreeNodePtr evaluate() const = 0;
virtual ~TreeNode() {}
virtual void PrintInPostFix(std::ostream&) const = 0;
protected:
TreeNodePtr left_;
TreeNodePtr right_;
};
class TreeNodeConstant : public TreeNode
{
public:
TreeNodeConstant(int value) : TreeNode(nullptr, nullptr), value_(value) {}
virtual TreeNodePtr derivate() const override {
return TreeNodePtr(new TreeNodeConstant(0));
}
int value() {
return value_;
}
virtual TreeNodePtr evaluate() const override {
return TreeNodePtr(new TreeNodeConstant(value_));
}
virtual void PrintInPostFix(std::ostream& output) const override {
output << value_ << " ";
}
private:
int value_;
};
class TreeNodeVar : public TreeNode {
public:
TreeNodeVar() : TreeNode(nullptr, nullptr) {}
virtual TreeNodePtr derivate() const override {
TreeNodePtr result = TreeNodePtr(new TreeNodeConstant(1));
return result;
}
virtual TreeNodePtr evaluate() const override {
return TreeNodePtr(new TreeNodeVar());
}
virtual void PrintInPostFix(std::ostream& stream) const override {
stream << "x ";
}
};
class TreeNodePlus : public TreeNode {
public:
TreeNodePlus(TreeNodePtr left, TreeNodePtr right) : TreeNode(std::move(left), std::move(right)) {}
virtual TreeNodePtr derivate() const override {
TreeNodePtr left = left_->derivate();
TreeNodePtr right = right_->derivate();
return TreeNodePtr(new TreeNodePlus(std::move(left), std::move(right)));
}
virtual TreeNodePtr evaluate() const override {
TreeNodePtr left = left_->evaluate();
TreeNodePtr right = right_->evaluate();
TreeNodeConstant* leftConstant = dynamic_cast<TreeNodeConstant *>(&*left);
TreeNodeConstant* rightConstant = dynamic_cast<TreeNodeConstant *>(&*right);
if (leftConstant != nullptr && rightConstant != nullptr) {
return TreeNodePtr(new TreeNodeConstant(leftConstant->value() + rightConstant->value()));
}
else {
return TreeNodePtr(new TreeNodePlus(std::move(left), std::move(right)));
}
}
virtual void PrintInPostFix(std::ostream& stream) const override {
left_->PrintInPostFix(stream);
right_->PrintInPostFix(stream);
stream << "+ ";
}
};
class TreeNodeMinus : public TreeNode {
public:
TreeNodeMinus(TreeNodePtr child) : TreeNode(std::move(child), nullptr) {}
virtual TreeNodePtr derivate() const override {
TreeNodePtr child = left_->derivate();
return TreeNodePtr(new TreeNodeMinus(std::move(child)));
}
virtual TreeNodePtr evaluate() const override {
TreeNodePtr child = left_->evaluate();
TreeNodeConstant* childConstant = dynamic_cast<TreeNodeConstant *>(&*child);
if (childConstant != nullptr ) {
return TreeNodePtr(new TreeNodeConstant(childConstant->value() * - 1));
}
else {
return TreeNodePtr(new TreeNodeMinus(std::move(child)));
}
}
virtual void PrintInPostFix(std::ostream& stream) const override {
left_->PrintInPostFix(stream);
stream << "- ";
}
};
class TreeNodeTimes : public TreeNode {
public:
TreeNodeTimes(TreeNodePtr left, TreeNodePtr right) : TreeNode(std::move(left), std::move(right)) {}
virtual TreeNodePtr derivate() const override {
TreeNodePtr leftDerivative = left_->derivate();
TreeNodePtr rightDerivative = right_->derivate();
TreeNodePtr left = TreeNodePtr(new TreeNodeTimes(std::move(leftDerivative), std::move(right_->evaluate())));
TreeNodePtr right = TreeNodePtr(new TreeNodeTimes(std::move(rightDerivative), std::move(left_->evaluate())));
return TreeNodePtr(new TreeNodePlus(std::move(left), std::move(right)));
}
virtual TreeNodePtr evaluate() const override {
TreeNodePtr left = left_->evaluate();
TreeNodePtr right = right_->evaluate();
TreeNodeConstant* leftConstant = dynamic_cast<TreeNodeConstant *>(&*left);
TreeNodeConstant* rightConstant = dynamic_cast<TreeNodeConstant *>(&*right);
if (leftConstant != nullptr && rightConstant != nullptr) {
return TreeNodePtr(new TreeNodeConstant(leftConstant->value() * rightConstant->value()));
}
else {
return TreeNodePtr(new TreeNodeTimes(std::move(left), std::move(right)));
}
}
virtual void PrintInPostFix(std::ostream& stream) const override {
left_->PrintInPostFix(stream);
right_->PrintInPostFix(stream);
stream << "* ";
}
};
inline void PrintInputError() {
std::cout << "Error input line!" << std::endl;
}
int main() {
std::string token;
std::stack<TreeNodePtr> stack;
while (std::getline(std::cin, token, ' ')) {
int size = token.size();
if (size > 0 && token[0] == '\n') {
token = token.substr(1);
}
if (token == "+") {
if (stack.size() < 2)
{
PrintInputError();
break;
}
TreeNodePtr right = std::move(stack.top()); stack.pop();
TreeNodePtr left = std::move(stack.top()); stack.pop();
stack.emplace(new TreeNodePlus(std::move(left), std::move(right)));
}
else if (token == "*") {
if (stack.size() < 2)
{
PrintInputError();
break;
}
TreeNodePtr right = std::move(stack.top()); stack.pop();
TreeNodePtr left = std::move(stack.top()); stack.pop();
stack.emplace(new TreeNodeTimes(std::move(left), std::move(right)));
}
else if (token == "-") {
if (stack.size() < 1)
{
PrintInputError();
break;
}
TreeNodePtr child = std::move(stack.top()); stack.pop();
stack.emplace(new TreeNodeMinus(std::move(child)));
}
else if (token == "x") {
stack.emplace(new TreeNodeVar());
}
else if (token == "d") {
if (stack.size() < 1)
{
PrintInputError();
break;
}
TreeNodePtr top = std::move(stack.top()); stack.pop();
TreeNodePtr result = top->derivate();
stack.push(std::move(result));
}
else if (token == "end") {
break;
}
else if (token == ".") {
if (stack.size() != 1)
{
PrintInputError();
break;
}
else {
stack.top()->evaluate()->PrintInPostFix(std::cout);
stack.pop();
std::cout << std::endl;
}
}
else {
int value = 0;
try {
value = std::stoi(token);
}
catch (...) {
PrintInputError();
break;
}
stack.emplace(new TreeNodeConstant(value));
}
}
}