From e50cc1d69c0f69e431af2b4eac683ee3c5e35e68 Mon Sep 17 00:00:00 2001 From: Jens Thiele Date: Mon, 20 Nov 2006 10:39:50 +0000 Subject: [PATCH] added start of code generator --- codegen/Makefile.am | 6 ++ codegen/README | 1 + codegen/main.cpp | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+), 0 deletions(-) create mode 100644 codegen/Makefile.am create mode 100644 codegen/README create mode 100644 codegen/main.cpp diff --git a/codegen/Makefile.am b/codegen/Makefile.am new file mode 100644 index 0000000..1f3846a --- /dev/null +++ b/codegen/Makefile.am @@ -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 index 0000000..f5ef756 --- /dev/null +++ b/codegen/README @@ -0,0 +1 @@ +code generator using gccxml and libxml++ diff --git a/codegen/main.cpp b/codegen/main.cpp new file mode 100644 index 0000000..e2f7bc0 --- /dev/null +++ b/codegen/main.cpp @@ -0,0 +1,232 @@ +#include +#include +#include + +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(*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(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 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(*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(node); + const xmlpp::TextNode* nodeText = dynamic_cast(node); + const xmlpp::CommentNode* nodeComment = dynamic_cast(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(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(pNode); + assert(root); + print_node(root); + } + } + catch(const std::exception& ex) + { + std::cout << "Exception caught: " << ex.what() << std::endl; + } + + return 0; +} -- 1.7.1