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