added start of code generator
[libt2n] / codegen / main.cpp
... / ...
CommitLineData
1#include <libxml++/libxml++.h>
2#include <cassert>
3#include <iostream>
4
5void 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*/
18const 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*/
40std::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*/
52std::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
79void 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
122void 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
203int 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}