1 /***************************************************************************
2 UlxrIdlParser.cpp - parse Ulxr idl files
3 -------------------
4 begin : Sun May 20 2007
5 copyright : (C) 2002-2007 by Ewald Arnold
6 email : ulxmlrpcpp@ewald-arnold.de
7
8 $Id: UlxrIdlParser.cpp 1151 2009-08-12 15:12:01Z ewald-arnold $
9
10 ***************************************************************************/
11
12 /**************************************************************************
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as
16 * published by the Free Software Foundation; either version 2 of the License,
17 * or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *
28 ***************************************************************************/
29
30 #include <cstring>
31
32 #include "UlxrIdlParser.h"
33 #include "xmlexcept.h"
34
35
36 /*
37 Ulxr-IDL : SOURCE
38 | INCLUDE
39 | CLASS
40 ;
41
42 CLASS : NAME
43 | LINK_SCOPE
44 | SUPER
45 | METHOD
46 | CONSTRUCTOR
47 ;
48
49 METHOD | CONSTRUCTOR : TYPE
50 | NAME
51 | ARG
52 ;
53
54 ARG : TYPE
55 | NAME
56 ;
57
58 */
59
60 #define TAG_ULXR_IDL "ULXR-IDL"
61
62 #define TAG_SOURCE "SOURCE"
63 #define TAG_INCLUDE "INCLUDE"
64 #define TAG_CLASS "CLASS"
65
66 #define TAG_FUNCTION "FUNCTION"
67
68 #define TAG_NAME "NAME"
69 #define TAG_LINK_SCOPE "LINK_SCOPE"
70 #define TAG_SUPER "SUPER"
71 #define TAG_METHOD "METHOD"
72 #define TAG_CONSTRUCTOR "CONSTRUCTOR"
73
74 #define TAG_TYPE "TYPE"
75 #define TAG_ARG "ARG"
76
77
UlxrIdlParser()78 UlxrIdlParser::UlxrIdlParser()
79 : XmlParser()
80 {
81 states.push(new ParserState(eNone));
82 }
83
84
~UlxrIdlParser()85 UlxrIdlParser::~UlxrIdlParser()
86 {
87 while (states.size() != 0)
88 {
89 delete states.top();
90 states.pop();
91 }
92 }
93
94
startElement(const XML_Char * name,const char ** atts)95 void UlxrIdlParser::startElement(const XML_Char* name, const char** atts)
96 {
97 if (!testStartElement(name, atts))
98 XmlParser::testStartElement(name, atts);
99 }
100
101
testStartElement(const XML_Char * name,const char ** atts)102 bool UlxrIdlParser::testStartElement(const XML_Char* name, const char** atts)
103 {
104 AttributeList attributes (this, atts);
105
106 switch(states.top()->getParserState() )
107 {
108 case eNone:
109 if(strcmp(name, TAG_ULXR_IDL) == 0)
110 {
111 in_arg = false;
112 in_method = false;
113 in_function = false;
114 theClass.setSource("");
115 functions.clear();
116 setComplete (false);
117 states.push(new ParserState(eUlxrIdl));
118 }
119
120 else
121 return false;
122 break;
123
124 case eUlxrIdl:
125 if(strcmp(name, TAG_SOURCE) == 0)
126 states.push(new ParserState(eSource));
127
128 else if(strcmp(name, TAG_INCLUDE) == 0)
129 states.push(new ParserState(eInclude));
130
131 else if(strcmp(name, TAG_CLASS) == 0)
132 {
133 theClass.clear();
134 states.push(new ParserState(eClass));
135 }
136
137 else if(strcmp(name, TAG_FUNCTION) == 0)
138 {
139 states.push(new ParserState(eFunction));
140 in_function = true;
141 method.clear();
142 method.setFunction(true);
143 }
144
145 else
146 return false;
147
148 break;
149
150 case eSuper:
151 if(strcmp(name, TAG_TYPE) == 0)
152 states.push(new ParserState(eType));
153
154 else
155 return false;
156
157 break;
158
159 case eClass:
160
161 if(strcmp(name, TAG_NAME) == 0)
162 states.push(new ParserState(eName));
163
164 else if(strcmp(name, TAG_LINK_SCOPE) == 0)
165 states.push(new ParserState(eLinkScope));
166
167 else if(strcmp(name, TAG_SUPER) == 0)
168 states.push(new ParserState(eSuper));
169
170 else if(strcmp(name, TAG_METHOD) == 0)
171 {
172 in_method = true;
173 method.clear();
174
175 AttributeList attribs(this, atts);
176
177 bool virt = false;
178 if (attribs.hasAttribute("virtual"))
179 virt = "1" == attribs.getAttribute("virtual");
180
181 bool cons = false;
182 if (attribs.hasAttribute("qual"))
183 cons = "const" == attribs.getAttribute("qual");
184
185 method.setProperty(false, virt, cons);
186
187 states.push(new ParserState(eMethod));
188 }
189
190 else if(strcmp(name, TAG_CONSTRUCTOR) == 0)
191 {
192 in_method = true;
193 method.clear();
194
195 AttributeList attribs(this, atts);
196
197 bool virt = false;
198 if (attribs.hasAttribute("virtual"))
199 virt = "1" == attribs.getAttribute("virtual");
200
201 bool cons = false;
202 if (attribs.hasAttribute("qual"))
203 cons = "const" == attribs.getAttribute("qual");
204
205 method.setProperty(true, virt, cons);
206
207 states.push(new ParserState(eConstructor));
208 }
209
210 else
211 return false;
212
213 break;
214
215 case eFunction:
216 case eMethod:
217 case eConstructor: // fallthrough
218 if(strcmp(name, TAG_TYPE) == 0)
219 {
220 AttributeList attribs(this, atts);
221
222 std::string left;
223 if (attribs.hasAttribute("qleft"))
224 left = attribs.getAttribute("qleft");
225
226 std::string right;
227 if (attribs.hasAttribute("qright"))
228 right = attribs.getAttribute("qright");
229
230 type.setProperty(left, right);
231
232 states.push(new ParserState(eType));
233 }
234
235 else if(strcmp(name, TAG_NAME) == 0)
236 states.push(new ParserState(eName));
237
238 else if(strcmp(name, TAG_ARG) == 0)
239 {
240 arg.clear();
241 in_arg = true;
242 states.push(new ParserState(eArg));
243 }
244
245 else
246 return false;
247
248 break;
249
250 case eArg:
251 if(strcmp(name, TAG_TYPE) == 0)
252 {
253 type.clear();
254
255 AttributeList attribs(this, atts);
256
257 std::string left;
258 if (attribs.hasAttribute("qleft"))
259 left= attribs.getAttribute("qleft");
260
261 std::string right;
262 if (attribs.hasAttribute("qright"))
263 right = attribs.getAttribute("qright");
264
265 type.setProperty(left, right);
266
267 states.push(new ParserState(eType));
268 }
269
270 else if(strcmp(name, TAG_NAME) == 0)
271 states.push(new ParserState(eName));
272
273 else
274 return false;
275
276 break;
277
278 default:
279 return false;
280 }
281
282 return true;
283 }
284
285
endElement(const XML_Char * name)286 void UlxrIdlParser::endElement(const XML_Char *name)
287 {
288 if (!testEndElement(name))
289 XmlParser::testEndElement(name);
290 }
291
292
testEndElement(const XML_Char * name)293 bool UlxrIdlParser::testEndElement(const XML_Char *name)
294 {
295 if (states.size() <= 1)
296 throw XmlException(NotWellformedError,
297 "Problem while parsing xml structure",
298 getCurrentLineNumber(),
299 std::string("abnormal program behaviour: UlxrIdlParser::testEndElement() had no states left: "));
300
301 ParserState *curr = states.top();
302 states.pop();
303
304 switch(curr->getParserState() )
305 {
306 case eUlxrIdl:
307 setComplete(true);
308 assertEndElement(name, TAG_ULXR_IDL);
309 break;
310
311 case eSource:
312 assertEndElement(name, TAG_SOURCE);
313 theClass.setSource(curr->getCharData());
314 method.setSource(curr->getCharData());
315 break;
316
317 case eInclude:
318 assertEndElement(name, TAG_INCLUDE);
319 break;
320
321 case eClass:
322 assertEndElement(name, TAG_CLASS);
323 classList.push_back(theClass);
324 break;
325
326 case eName:
327 assertEndElement(name, TAG_NAME);
328
329 if (in_arg)
330 arg.setName(curr->getCharData());
331
332 else if (in_method || in_function)
333 method.setName(theClass.getName(), curr->getCharData());
334
335 else
336 theClass.setName(curr->getCharData());
337 break;
338
339 case eLinkScope:
340 assertEndElement(name, TAG_LINK_SCOPE);
341 break;
342
343 case eSuper:
344 assertEndElement(name, TAG_SUPER);
345 break;
346
347 case eFunction:
348 assertEndElement(name, TAG_FUNCTION);
349
350 functions.push_back(method);
351 in_function = false;
352 break;
353
354 case eMethod:
355 assertEndElement(name, TAG_METHOD);
356
357 theClass.addMethod(method);
358 in_method = false;
359 break;
360
361 case eConstructor:
362 assertEndElement(name, TAG_CONSTRUCTOR);
363
364 theClass.addMethod(method);
365 in_method = false;
366 break;
367
368 case eType:
369 assertEndElement(name, TAG_TYPE);
370
371 type.setName(curr->getCharData());
372
373 if (in_arg)
374 arg.setType(type);
375
376 else if (in_method || in_function)
377 method.setType(type);
378
379 // else eSuper
380 break;
381
382 case eArg:
383 assertEndElement(name, TAG_ARG);
384 in_arg = false;
385 method.addArgument(arg);
386 break;
387
388 default:
389 states.push(curr); // put back, someone else will process
390 return false;
391 }
392
393 delete curr;
394 return true;
395 }
396
397
numClasses() const398 unsigned UlxrIdlParser::numClasses() const
399 {
400 return classList.size();
401 }
402
403
getFunctions() const404 std::vector<Method> UlxrIdlParser::getFunctions() const
405 {
406 return functions;
407 }
408
409
getClass(unsigned i) const410 UlxrIdlClass UlxrIdlParser::getClass(unsigned i) const
411 {
412 return classList[i];
413 }
414
415