added start of code generator
authorJens Thiele <jens.thiele@intra2net.com>
Mon, 20 Nov 2006 10:39:50 +0000 (10:39 +0000)
committerJens Thiele <jens.thiele@intra2net.com>
Mon, 20 Nov 2006 10:39:50 +0000 (10:39 +0000)
codegen/Makefile.am [new file with mode: 0644]
codegen/README [new file with mode: 0644]
codegen/main.cpp [new file with mode: 0644]

diff --git a/codegen/Makefile.am b/codegen/Makefile.am
new file mode 100644 (file)
index 0000000..1f3846a
--- /dev/null
@@ -0,0 +1,6 @@
+INCLUDES = @CODEGEN_CFLAGS@
+LDADD = @CODEGEN_LIBS@
+
+codegen_SOURCES = main.cpp
+
+bin_PROGRAMS = codegen
diff --git a/codegen/README b/codegen/README
new file mode 100644 (file)
index 0000000..f5ef756
--- /dev/null
@@ -0,0 +1 @@
+code generator using gccxml and libxml++
diff --git a/codegen/main.cpp b/codegen/main.cpp
new file mode 100644 (file)
index 0000000..e2f7bc0
--- /dev/null
@@ -0,0 +1,232 @@
+#include <libxml++/libxml++.h>
+#include <cassert>
+#include <iostream>
+
+void print_indentation(unsigned int indentation)
+{
+     for(unsigned int i = 0; i < indentation; ++i)
+         std::cout << " ";
+}
+
+
+
+//! get child element by id
+/*!
+  \return pointer to element having id or null on error
+  \todo find libxmlpp pendant
+*/
+const xmlpp::Element* get_element_by_id(const xmlpp::Element* element, const std::string &id)
+{
+     const xmlpp::Attribute* cid = element->get_attribute("id");
+     if ( cid && ( cid->get_value() == id)) return element;
+
+     //Recurse through child nodes:
+     xmlpp::Node::NodeList list = element->get_children();
+     for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
+     {
+         const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(*iter);
+         if (element) {
+              const xmlpp::Element* match = get_element_by_id(element, id);
+              if (match) return match;
+         }
+     }
+     return NULL;
+}
+
+//! get namespace by id
+/*!
+  \return namespace name or empty string on error
+*/
+std::string get_namespace(const xmlpp::Element* root, const std::string &id)
+{
+     std::string error;
+     const xmlpp::Element* element(get_element_by_id(root, id));
+     if ((!element)||(!element->get_attribute("name"))) return error;
+     return element->get_attribute("name")->get_value();
+}
+
+//! get type by id
+/*!
+  \return type name or empty string on error
+*/
+std::string get_type(const xmlpp::Element* root, const std::string &id)
+{
+     std::string error;
+     const xmlpp::Element* element(get_element_by_id(root, id));
+     if (!element) return error;
+
+     // TODO: not yet complete
+     // if we recurse - when do we stop?
+     // if it is a typedef? yes? (hmm if the typedef is in the file parsed this will not work)
+     std::string tag(element->get_name());
+     if (tag=="ReferenceType") {
+         assert(element->get_attribute("type"));
+         std::string ret(get_type(root, element->get_attribute("type")->get_value()));
+         if (ret==error) return error;
+         return ret+"&";
+     }else if (tag=="CvQualifiedType") {
+         assert(element->get_attribute("type"));
+         std::string ret(get_type(root, element->get_attribute("type")->get_value()));
+         if (ret==error) return error;
+         return std::string("const ")+ret;
+     }
+
+     assert(element->get_attribute("name"));
+     assert(element->get_attribute("context"));
+     return get_namespace(root, element->get_attribute("context")->get_value())+"::"+element->get_attribute("name")->get_value();
+}
+
+void parse_function(const xmlpp::Element* root, const xmlpp::Node* node, unsigned int indentation = 0) {
+     const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(node);
+     if (!element) return;
+
+     const xmlpp::Attribute* attributes = element->get_attribute("attributes");
+     const xmlpp::Attribute* name = element->get_attribute("name");
+     const xmlpp::Attribute* returns = element->get_attribute("returns");
+     if ((!attributes)||(!name)||(!returns)) return;
+
+     // check wether the function is marked (TODO: improve)
+     if (attributes->get_value().find("gccxml(libt2n")==std::string::npos) return;
+
+     // TODO: extract command group
+     // something like: sed 's,gccxml(libt2n-\([a-z]*}),\1,'
+
+     // we need the return type
+     std::string ret_type(get_type(root, returns->get_value()));
+
+     // and the argument types
+     typedef std::map<std::string, std::string> Args;
+     Args  args;
+
+     xmlpp::Node::NodeList list = node->get_children("Argument");
+     for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
+     {
+         const xmlpp::Element* arg = dynamic_cast<const xmlpp::Element*>(*iter);
+         if ( arg ) {
+              assert(arg->get_name() == "Argument");
+              assert(arg->get_attribute("name"));
+              assert(arg->get_attribute("type"));
+              assert(args.find(arg->get_attribute("name")->get_value())==args.end());
+              args[arg->get_attribute("name")->get_value()]=get_type(root, arg->get_attribute("type")->get_value());
+         }
+     }
+
+     std::cerr << "Found marked Function: " << ret_type << " " << name->get_value() << "(";
+     for (Args::const_iterator it=args.begin();it!=args.end();++it) {
+         if (it!=args.begin()) std::cerr << ", ";
+         std::cerr << it->second << " " << it->first;
+     }
+     std::cerr << ");" << std::endl;
+}
+
+void print_node(const xmlpp::Element* root, const xmlpp::Node* node = NULL, unsigned int indentation = 0)
+{
+     if (!node) node=root;
+     std::cout << std::endl; //Separate nodes by an empty line.
+  
+     const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
+     const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::TextNode*>(node);
+     const xmlpp::CommentNode* nodeComment = dynamic_cast<const xmlpp::CommentNode*>(node);
+
+     if(nodeText && nodeText->is_white_space()) //Let's ignore the indenting - you don't always want to do this.
+         return;
+    
+     std::string nodename = node->get_name();
+
+     if(!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text".
+     {
+         print_indentation(indentation);
+         //    std::cout << "Node name = " << node->get_name() << std::endl;
+         //    std::cout << "Node name = " << nodename << std::endl;
+         if (node->get_name() == "Function") {
+              parse_function(root, node, indentation);
+         }
+     }
+     else if(nodeText) //Let's say when it's text. - e.g. let's say what that white space is.
+     {
+         print_indentation(indentation);
+         std::cout << "Text Node" << std::endl;
+     }
+
+     //Treat the various node types differently: 
+     if(nodeText)
+     {
+         print_indentation(indentation);
+         std::cout << "text = \"" << nodeText->get_content() << "\"" << std::endl;
+     }
+     else if(nodeComment)
+     {
+         print_indentation(indentation);
+         std::cout << "comment = " << nodeComment->get_content() << std::endl;
+     }
+     else if(nodeContent)
+     {
+         print_indentation(indentation);
+         std::cout << "content = " << nodeContent->get_content() << std::endl;
+     }
+     else if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node))
+     {
+         //A normal Element node:
+
+         //line() works only for ElementNodes.
+         print_indentation(indentation);
+         std::cout << "     line = " << node->get_line() << std::endl;
+
+         //Print attributes:
+         const xmlpp::Element::AttributeList& attributes = nodeElement->get_attributes();
+         for(xmlpp::Element::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
+         {
+              const xmlpp::Attribute* attribute = *iter;
+              print_indentation(indentation);
+              std::cout << "  Attribute " << attribute->get_name() << " = " << attribute->get_value() << std::endl;
+         }
+
+         const xmlpp::Attribute* attribute = nodeElement->get_attribute("title");
+         if(attribute)
+         {
+              std::cout << "title found: =" << attribute->get_value() << std::endl;
+      
+         }
+     }
+  
+     if(!nodeContent)
+     {
+         //Recurse through child nodes:
+         xmlpp::Node::NodeList list = node->get_children();
+         for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
+         {
+              print_node(root, *iter, indentation + 2); //recursive
+         }
+     }
+}
+
+int main(int argc, char* argv[])
+{
+     std::string filepath;
+     if(argc > 1 )
+         filepath = argv[1]; //Allow the user to specify a different XML file to parse.
+     else
+         filepath = "example.xml";
+  
+     try
+     {
+         xmlpp::DomParser parser;
+         //    parser.set_validate();
+         parser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically.
+         parser.parse_file(filepath);
+         if(parser)
+         {
+              //Walk the tree:
+              const xmlpp::Node* pNode = parser.get_document()->get_root_node(); //deleted by DomParser.
+              const xmlpp::Element* root = dynamic_cast<const xmlpp::Element*>(pNode);
+              assert(root);
+              print_node(root);
+         }
+     }
+     catch(const std::exception& ex)
+     {
+         std::cout << "Exception caught: " << ex.what() << std::endl;
+     }
+
+     return 0;
+}