$ template make_node() $ $ // Generate the node.cpp file $ output $basedir + '/node.cpp' /* This file was generated by SableCC (http://www.sablecc.org/). */ #include "node.h" #include "list.h" #include "token.h" struct $namespace::_NodeData { List list; Node node; }; $namespace::Exception::~Exception () { } $namespace::_GenericNode::_GenericNode () { } $namespace::_GenericNode::~_GenericNode () { for ( size_t i = 0; i < nodes.size(); i++ ) { if ( type_info->prod_elem_is_list[i] ) nodes[i].list.clear(); else if ( nodes[i].node ) nodes[i].node.parent(0); } } $namespace::_GenericNode *$namespace::_GenericNode::initToken (const _TypeInfo *type_info, int line, int pos, const std::string& text) { _GenericNode *node = new _GenericNode(); node->ref_count = 0; node->parent = 0; node->type_info = type_info; node->line = line; node->pos = pos; node->text = text; return node; } $namespace::_GenericNode *$namespace::_GenericNode::initProd (const _TypeInfo *type_info, void **args) { _GenericNode *node = new _GenericNode(); node->ref_count = 0; node->parent = 0; node->type_info = type_info; node->nodes.resize (type_info->prod_elem_count); for ( size_t i = 0; i < node->nodes.size(); i++ ) { if ( type_info->prod_elem_is_list[i] ) node->nodes[i].list.setOwner(node); } if ( args ) { for ( size_t i = 0; i < node->nodes.size(); i++ ) { if ( type_info->prod_elem_is_list[i] ) _List_helper::assign (node, node->nodes[i].list.list, 0, *((_List_helper::list_t*)args[i])); else node->setChildNode (i, *((Node *)args[i])); } } return node; } $namespace::Node $namespace::_GenericNode::clone () const { _GenericNode *node = new _GenericNode (); node->type_info = type_info; node->ref_count = 0; node->parent = 0; node->text = text; node->line = line; node->pos = pos; node->nodes.resize (type_info->prod_elem_count); for ( size_t i = 0; i < node->nodes.size(); i++ ) { if ( type_info->prod_elem_is_list[i] ) { node->nodes[i].list.setOwner(node); for ( std::list::const_iterator it = nodes[i].list.list.begin(); it != nodes[i].list.list.end(); it++ ) { node->nodes[i].list.push_back (it->clone()); } } else { node->nodes[i].node = nodes[i].node.clone(); } } return node; } std::string $namespace::_GenericNode::toString () const { if ( type_info->type == _TypeInfo::is_token ) return text + " "; std::string ret; for ( size_t i = 0; i < nodes.size(); i++ ) { if ( type_info->prod_elem_is_list[i] ) { for ( std::list::const_iterator it = nodes[i].list.list.begin(); it != nodes[i].list.list.end(); it++ ) { ret += (*it).toString(); } } else { if ( nodes[i].node ) ret += nodes[i].node.toString(); } } return ret; } $namespace::Node $namespace::_GenericNode::getChildNode (int id) { return nodes[id].node; } $namespace::List<$namespace::Node>& $namespace::_GenericNode::getChildList (int id) { return nodes[id].list; } void $namespace::_GenericNode::setChildNode (int id, Node node) { Node &var = nodes[id].node; if ( var ) var.parent(0); if ( node ) { if ( node.parent() ) node.parent().removeChild (node); node.parent (this); } var = node; } void $namespace::_GenericNode::removeChild (Node node) { if ( !node ) throw (Exception ("_GenericNode::removeChild: null given, invalid condition, this should not happen!")); for ( size_t i = 0; i < nodes.size(); i++ ) { if ( type_info->prod_elem_is_list[i] ) { if ( nodes[i].list.erase(node) ) return; } else { if ( nodes[i].node == node ) { nodes[i].node = Node(); return; } } } } void $namespace::_GenericNode::replaceChild (Node old_child, Node new_child) { if ( !old_child ) throw (Exception ("_GenericNode::replaceChild: null given, invalid condition, this should not happen!")); for ( size_t i = 0; i < nodes.size(); i++ ) { if ( type_info->prod_elem_is_list[i] ) { if ( nodes[i].list.replace (old_child, new_child) ) return; } else { if ( nodes[i].node == old_child ) { setChildNode (i, new_child); return; } } } } void $namespace::_GenericNode::replaceBy (Node node) { if ( !parent || node.obj == this ) return; // no point with no parent and no can do replacing by ourselves if ( !node ) { parent->removeChild (this); } else { // now we have to do complicated type checks // 1) if we are token then node must be token and our types must match if ( type_info->is(&Token::type_info) ) { if ( type_info->type_id != node.type_id() ) throw Exception (std::string("replaceBy: trying to replace a token of different type, must be '") + type_info->name + "', '" + node.type_name() + "' given"); } else { // 2) Expected prod but we got token if ( node.is() ) throw Exception (std::string("replaceBy: trying to replace a production with token, must be '") + type_info->parent->name + "', '" + node.type_name() + "' given"); // 3) now we can assume we have productions here, node must share the parent type of this type if ( node.obj->type_info->parent->type_id != type_info->parent->type_id ) throw Exception (std::string("replaceBy: in this context given node must be of type '") + type_info->parent->name + "', '" + node.obj->type_info->parent->name + "' given"); } parent->replaceChild (this, node); } } $ end output $ // Generate the node.h file $ output $incdir + '/node.h' /* This file was generated by SableCC (http://www.sablecc.org/). */ #ifndef __${$namespace}__node_hh__ #define __${$namespace}__node_hh__ #include #include #include namespace $namespace { class Analysis; class Node; class Token; class _GenericNode; template class List; struct _TypeInfo { const char *name; const _TypeInfo *parent; int type_id; int token_index; bool token_is_mutable; int prod_elem_count; int *prod_elem_is_list; enum { is_token, is_prod, is_other } type; typedef void (Analysis::* apply_t)(Node); apply_t apply_ptr; private: friend class Node; friend class _GenericNode; bool is (const _TypeInfo *info) const; void apply (Analysis& analysis, Node& node) const; }; struct _NodeData; class _GenericNode { private: _GenericNode (); ~_GenericNode (); // fields for alternatives std::vector<_NodeData> nodes; // fields for Token std::string text; int line; int pos; // typeinfo const _TypeInfo *type_info; // parent _GenericNode *parent; int ref_count; friend class Node; friend class Token; friend class Lexer; friend class Parser; static _GenericNode* initToken (const _TypeInfo *type_info, int line, int pos, const std::string& text); static _GenericNode* initProd (const _TypeInfo *type_info, void **args); Node getChildNode (int id); void setChildNode (int id, Node node); List& getChildList (int id); void removeChild (Node node); void replaceChild (Node old_child, Node new_child); void replaceBy (Node node); std::string toString() const; Node clone () const; }; class Node { public: inline Node () : obj(0) { } inline Node (const Node& node) : obj(node.obj) { if (obj) obj->ref_count++; } inline Node& operator= (const Node& node) { if (obj && !--obj->ref_count) delete obj; obj = node.obj; if (obj) obj->ref_count++; return *this; } inline ~Node () { if ( obj && !--obj->ref_count) delete obj; } inline operator bool () const { return obj != 0; } template inline T& unsafe_cast () { return reinterpret_cast(*this); } template inline bool is() { return ptr()->type_info->is(&T::type_info); } template inline T cast () { if ( is() ) return unsafe_cast(); else return T(); } inline Node parent() { return ptr()->parent; } static const _TypeInfo type_info; inline std::string toString() const { return ptr()->toString(); } inline void replaceBy (Node node) { return ptr()->replaceBy(node); } inline void apply (Analysis& analysis) { ptr()->type_info->apply (analysis, *this); } inline const char * type_name() const { return ptr()->type_info->name; } inline int type_id() const { return ptr()->type_info->type_id; } inline Node clone () const { return ptr()->clone(); } friend inline bool operator== (const Node& l, const Node& r) { return l.obj == r.obj; } friend inline bool operator!= (const Node& l, const Node& r) { return l.obj != r.obj; } protected: inline Node (_GenericNode *obj) : obj(obj) { if (obj) obj->ref_count++; } inline _GenericNode *ptr () { return obj; } inline const _GenericNode *ptr () const { return obj; } static inline _GenericNode *initProd (const _TypeInfo *type_info) { return _GenericNode::initProd(type_info, (void **)0); } static inline _GenericNode *initProd (const _TypeInfo *type_info, void **args) { return _GenericNode::initProd(type_info, args); } inline Node getChildNode (int id) { return ptr()->getChildNode(id); } inline void setChildNode (int id, Node node) { ptr()->setChildNode(id, node); } inline List& getChildList (int id) { return ptr()->getChildList(id); } template static inline std::list& getListGuts (List& list) { return list.list; } private: mutable _GenericNode *obj; inline void parent (_GenericNode *p) { ptr()->parent = p; } inline void removeChild (Node node) { ptr()->removeChild(node); } inline void replaceChild (Node old_child, Node new_child) { ptr()->replaceChild(old_child, new_child); } friend class _GenericNode; friend class _List_helper; friend class Parser; }; class Exception { public: inline Exception (const std::string& msg) : msg(msg) { } inline const std::string& getMessage () const { return msg; } virtual ~Exception (); private: std::string msg; }; } #endif // ! __${$namespace}__node_hh__ $ end output $ // Generate the all.h file $ if $build_system $ output $incdir + '/all.h' /* This file was generated by SableCC (http://www.sablecc.org/). */ #ifndef __${$namespace}__all_hh__ #define __${$namespace}__all_hh__ #include "$libname/node.h" #include "$libname/token.h" #include "$libname/lexer.h" #include "$libname/list.h" #include "$libname/prod.h" #include "$libname/parser.h" #include "$libname/analysis.h" #endif // ! __${$namespace}__all_hh__ $ end output $ end if $ end template