/* Copyright (C) 2020-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include // nullptr_t #include #include // Type erasure 101 . class NodeInterface; class Node { public: Node (const Node& node) = default; Node (Node&& node) = default; Node () = default; ~Node () = default; template >::value, int>* = nullptr> Node (T&& t); Node& operator= (const Node& node) = default; Node& operator= (Node&& node) = default; explicit operator bool () const { return impl_ != nullptr; } std::ostream& print (std::ostream& o) const; std::shared_ptr impl_; }; static std::ostream& operator<< (std::ostream& o, const Node &node) { return node.print (o); } class NodeInterface { public: virtual ~NodeInterface () = default; virtual std::ostream& print (std::ostream& o) const = 0; }; std::ostream& Node::print (std::ostream& o) const { if (impl_) impl_->print (o); return o; } template >::value, int>* = nullptr> struct NodeImpl : public NodeInterface { template explicit NodeImpl (U&& u) : t{std::forward (u)} {} virtual ~NodeImpl () = default; virtual std::ostream& print (std::ostream& o) const { return o << t; } T t; }; template >::value, int>*> Node::Node (T&& t) : impl_ (new NodeImpl>{std::forward (t)}) {} class Nterm { public: Nterm (std::string form, Node child0 = Node (), Node child1 = Node (), Node child2 = Node ()) : form_ (std::move (form)) { children_[0] = child0; children_[1] = child1; children_[2] = child2; } friend std::ostream& operator<< (std::ostream& o, const Nterm& t) { o << t.form_; if (t.children_[0]) { o << '(' << t.children_[0]; if (t.children_[1]) o << ", " << t.children_[1]; if (t.children_[2]) o << ", " << t.children_[2]; o << ')'; } return o; } private: std::string form_; Node children_[3]; }; class Term { public: Term (std::string text) : text_ (std::move (text)) {} friend std::ostream& operator<< (std::ostream& o, const Term& t) { return o << t.text_; } private: std::string text_; }; #ifdef TEST int main () { Node n0; std::cout << n0 << '\n'; Node n; n = n0; std::cout << n0 << '\n'; Term t1 = Term ("T"); std::cout << t1 << '\n'; n = t1; std::cout << n << '\n'; std::cout << Nterm ("+", t1, t1) << '\n'; auto n1 = Nterm ("", Nterm ("", Term ("T"), Term ("x")), Nterm ("", Term ("x"), Term ("T"))); std::cout << n1 << '\n'; n = n1; std::cout << n1 << '\n'; } #endif