added start of code generator
[libt2n] / codegen / main.cpp
1 #include <libxml++/libxml++.h>
2 #include <cassert>
3 #include <iostream>
4
5 void print_indentation(unsigned int indentation)
6 {
7      for(unsigned int i = 0; i < indentation; ++i)
8           std::cout << " ";
9 }
10
11
12
13 //! get child element by id
14 /*!
15   \return pointer to element having id or null on error
16   \todo find libxmlpp pendant
17 */
18 const xmlpp::Element* get_element_by_id(const xmlpp::Element* element, const std::string &id)
19 {
20      const xmlpp::Attribute* cid = element->get_attribute("id");
21      if ( cid && ( cid->get_value() == id)) return element;
22
23      //Recurse through child nodes:
24      xmlpp::Node::NodeList list = element->get_children();
25      for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
26      {
27           const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(*iter);
28           if (element) {
29                const xmlpp::Element* match = get_element_by_id(element, id);
30                if (match) return match;
31           }
32      }
33      return NULL;
34 }
35
36 //! get namespace by id
37 /*!
38   \return namespace name or empty string on error
39 */
40 std::string get_namespace(const xmlpp::Element* root, const std::string &id)
41 {
42      std::string error;
43      const xmlpp::Element* element(get_element_by_id(root, id));
44      if ((!element)||(!element->get_attribute("name"))) return error;
45      return element->get_attribute("name")->get_value();
46 }
47
48 //! get type by id
49 /*!
50   \return type name or empty string on error
51 */
52 std::string get_type(const xmlpp::Element* root, const std::string &id)
53 {
54      std::string error;
55      const xmlpp::Element* element(get_element_by_id(root, id));
56      if (!element) return error;
57
58      // TODO: not yet complete
59      // if we recurse - when do we stop?
60      // if it is a typedef? yes? (hmm if the typedef is in the file parsed this will not work)
61      std::string tag(element->get_name());
62      if (tag=="ReferenceType") {
63           assert(element->get_attribute("type"));
64           std::string ret(get_type(root, element->get_attribute("type")->get_value()));
65           if (ret==error) return error;
66           return ret+"&";
67      }else if (tag=="CvQualifiedType") {
68           assert(element->get_attribute("type"));
69           std::string ret(get_type(root, element->get_attribute("type")->get_value()));
70           if (ret==error) return error;
71           return std::string("const ")+ret;
72      }
73
74      assert(element->get_attribute("name"));
75      assert(element->get_attribute("context"));
76      return get_namespace(root, element->get_attribute("context")->get_value())+"::"+element->get_attribute("name")->get_value();
77 }
78
79 void parse_function(const xmlpp::Element* root, const xmlpp::Node* node, unsigned int indentation = 0) {
80      const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(node);
81      if (!element) return;
82
83      const xmlpp::Attribute* attributes = element->get_attribute("attributes");
84      const xmlpp::Attribute* name = element->get_attribute("name");
85      const xmlpp::Attribute* returns = element->get_attribute("returns");
86      if ((!attributes)||(!name)||(!returns)) return;
87
88      // check wether the function is marked (TODO: improve)
89      if (attributes->get_value().find("gccxml(libt2n")==std::string::npos) return;
90
91      // TODO: extract command group
92      // something like: sed 's,gccxml(libt2n-\([a-z]*}),\1,'
93
94      // we need the return type
95      std::string ret_type(get_type(root, returns->get_value()));
96
97      // and the argument types
98      typedef std::map<std::string, std::string> Args;
99      Args  args;
100
101      xmlpp::Node::NodeList list = node->get_children("Argument");
102      for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
103      {
104           const xmlpp::Element* arg = dynamic_cast<const xmlpp::Element*>(*iter);
105           if ( arg ) {
106                assert(arg->get_name() == "Argument");
107                assert(arg->get_attribute("name"));
108                assert(arg->get_attribute("type"));
109                assert(args.find(arg->get_attribute("name")->get_value())==args.end());
110                args[arg->get_attribute("name")->get_value()]=get_type(root, arg->get_attribute("type")->get_value());
111           }
112      }
113
114      std::cerr << "Found marked Function: " << ret_type << " " << name->get_value() << "(";
115      for (Args::const_iterator it=args.begin();it!=args.end();++it) {
116           if (it!=args.begin()) std::cerr << ", ";
117           std::cerr << it->second << " " << it->first;
118      }
119      std::cerr << ");" << std::endl;
120 }
121
122 void print_node(const xmlpp::Element* root, const xmlpp::Node* node = NULL, unsigned int indentation = 0)
123 {
124      if (!node) node=root;
125      std::cout << std::endl; //Separate nodes by an empty line.
126   
127      const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
128      const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::TextNode*>(node);
129      const xmlpp::CommentNode* nodeComment = dynamic_cast<const xmlpp::CommentNode*>(node);
130
131      if(nodeText && nodeText->is_white_space()) //Let's ignore the indenting - you don't always want to do this.
132           return;
133     
134      std::string nodename = node->get_name();
135
136      if(!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text".
137      {
138           print_indentation(indentation);
139           //    std::cout << "Node name = " << node->get_name() << std::endl;
140           //    std::cout << "Node name = " << nodename << std::endl;
141           if (node->get_name() == "Function") {
142                parse_function(root, node, indentation);
143           }
144      }
145      else if(nodeText) //Let's say when it's text. - e.g. let's say what that white space is.
146      {
147           print_indentation(indentation);
148           std::cout << "Text Node" << std::endl;
149      }
150
151      //Treat the various node types differently: 
152      if(nodeText)
153      {
154           print_indentation(indentation);
155           std::cout << "text = \"" << nodeText->get_content() << "\"" << std::endl;
156      }
157      else if(nodeComment)
158      {
159           print_indentation(indentation);
160           std::cout << "comment = " << nodeComment->get_content() << std::endl;
161      }
162      else if(nodeContent)
163      {
164           print_indentation(indentation);
165           std::cout << "content = " << nodeContent->get_content() << std::endl;
166      }
167      else if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node))
168      {
169           //A normal Element node:
170
171           //line() works only for ElementNodes.
172           print_indentation(indentation);
173           std::cout << "     line = " << node->get_line() << std::endl;
174
175           //Print attributes:
176           const xmlpp::Element::AttributeList& attributes = nodeElement->get_attributes();
177           for(xmlpp::Element::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
178           {
179                const xmlpp::Attribute* attribute = *iter;
180                print_indentation(indentation);
181                std::cout << "  Attribute " << attribute->get_name() << " = " << attribute->get_value() << std::endl;
182           }
183
184           const xmlpp::Attribute* attribute = nodeElement->get_attribute("title");
185           if(attribute)
186           {
187                std::cout << "title found: =" << attribute->get_value() << std::endl;
188       
189           }
190      }
191   
192      if(!nodeContent)
193      {
194           //Recurse through child nodes:
195           xmlpp::Node::NodeList list = node->get_children();
196           for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
197           {
198                print_node(root, *iter, indentation + 2); //recursive
199           }
200      }
201 }
202
203 int main(int argc, char* argv[])
204 {
205      std::string filepath;
206      if(argc > 1 )
207           filepath = argv[1]; //Allow the user to specify a different XML file to parse.
208      else
209           filepath = "example.xml";
210   
211      try
212      {
213           xmlpp::DomParser parser;
214           //    parser.set_validate();
215           parser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically.
216           parser.parse_file(filepath);
217           if(parser)
218           {
219                //Walk the tree:
220                const xmlpp::Node* pNode = parser.get_document()->get_root_node(); //deleted by DomParser.
221                const xmlpp::Element* root = dynamic_cast<const xmlpp::Element*>(pNode);
222                assert(root);
223                print_node(root);
224           }
225      }
226      catch(const std::exception& ex)
227      {
228           std::cout << "Exception caught: " << ex.what() << std::endl;
229      }
230
231      return 0;
232 }