|
1 /****************************************************************************** |
|
2 * |
|
3 * |
|
4 * |
|
5 * Copyright (C) 1997-2008 by Dimitri van Heesch. |
|
6 * |
|
7 * Permission to use, copy, modify, and distribute this software and its |
|
8 * documentation under the terms of the GNU General Public License is hereby |
|
9 * granted. No representations are made about the suitability of this software |
|
10 * for any purpose. It is provided "as is" without express or implied warranty. |
|
11 * See the GNU General Public License for more details. |
|
12 * |
|
13 * Documents produced by Doxygen are derivative works derived from the |
|
14 * input used in their production; they are not affected by this license. |
|
15 * |
|
16 */ |
|
17 |
|
18 /*! \file |
|
19 * This scanner is used to convert a string into a list of function or |
|
20 * template arguments. Each parsed argument results in a Argument struct, |
|
21 * that is put into an ArgumentList in declaration order. |
|
22 * Comment blocks for arguments can also be included in the string. |
|
23 * The argument string does not contain new-lines (except inside any |
|
24 * comment blocks). |
|
25 * An Argument consists of the string fields: |
|
26 * type,name,default value, and documentation |
|
27 * The Argument list as a whole can be pure, constant or volatile. |
|
28 * |
|
29 * Examples of input strings are: |
|
30 * \code |
|
31 * "(int a,int b) const" |
|
32 * "(const char *s="hello world",int=5) = 0" |
|
33 * "<class T,class N>" |
|
34 * "(char c,const char)" |
|
35 * \endcode |
|
36 * |
|
37 * Note: It is not always possible to distinguish between the name and |
|
38 * type of an argument. In case of doubt the name is added to the |
|
39 * type, and the matchArgumentList in util.cpp is be used to |
|
40 * further determine the correct separation. |
|
41 */ |
|
42 |
|
43 %{ |
|
44 |
|
45 /* |
|
46 * includes |
|
47 */ |
|
48 #include "qtbc.h" |
|
49 #include <stdio.h> |
|
50 //#include <iostream.h> |
|
51 #include <assert.h> |
|
52 #include <ctype.h> |
|
53 #include <qregexp.h> |
|
54 |
|
55 #include "defargs.h" |
|
56 #include "entry.h" |
|
57 #include "util.h" |
|
58 |
|
59 #define YY_NEVER_INTERACTIVE 1 |
|
60 |
|
61 /* ----------------------------------------------------------------- |
|
62 * state variables |
|
63 */ |
|
64 static const char *g_inputString; |
|
65 static int g_inputPosition; |
|
66 static ArgumentList *g_argList; |
|
67 static QCString *g_copyArgValue; |
|
68 static QCString g_curArgTypeName; |
|
69 static QCString g_curArgDefValue; |
|
70 static QCString g_curArgName; |
|
71 static QCString g_curArgDocs; |
|
72 static QCString g_curArgAttrib; |
|
73 static QCString g_curArgArray; |
|
74 static QCString g_extraTypeChars; |
|
75 static int g_argRoundCount; |
|
76 static int g_argSharpCount; |
|
77 static int g_argCurlyCount; |
|
78 static int g_readArgContext; |
|
79 static int g_lastDocContext; |
|
80 static int g_lastDocChar; |
|
81 |
|
82 /* ----------------------------------------------------------------- |
|
83 */ |
|
84 #undef YY_INPUT |
|
85 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); |
|
86 |
|
87 static int yyread(char *buf,int max_size) |
|
88 { |
|
89 int c=0; |
|
90 while( c < max_size && g_inputString[g_inputPosition] ) |
|
91 { |
|
92 *buf = g_inputString[g_inputPosition++] ; |
|
93 c++; buf++; |
|
94 } |
|
95 return c; |
|
96 } |
|
97 |
|
98 %} |
|
99 |
|
100 B [ \t] |
|
101 ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* |
|
102 |
|
103 %option noyywrap |
|
104 |
|
105 %x Start |
|
106 %x CopyArgString |
|
107 %x CopyArgRound |
|
108 %x CopyArgRound2 |
|
109 %x CopyArgSharp |
|
110 %x CopyArgCurly |
|
111 %x ReadFuncArgType |
|
112 %x ReadFuncArgDef |
|
113 %x ReadFuncArgPtr |
|
114 %x FuncQual |
|
115 %x ReadDocBlock |
|
116 %x ReadDocLine |
|
117 |
|
118 |
|
119 %% |
|
120 |
|
121 <Start>[<(] { BEGIN(ReadFuncArgType); } |
|
122 |
|
123 <ReadFuncArgType>{B}* { |
|
124 g_curArgTypeName+=" "; |
|
125 } |
|
126 <ReadFuncArgType>"["[^\]]*"]" { |
|
127 if (g_curArgTypeName.stripWhiteSpace().isEmpty()) |
|
128 { |
|
129 g_curArgAttrib=yytext; // for M$-IDL |
|
130 } |
|
131 else // array type |
|
132 { |
|
133 g_curArgArray+=yytext; |
|
134 } |
|
135 } |
|
136 <ReadFuncArgDef>"'"\\[0-7]{1,3}"'" { g_curArgDefValue+=yytext; } |
|
137 <ReadFuncArgDef>"'"\\."'" { g_curArgDefValue+=yytext; } |
|
138 <ReadFuncArgDef>"'"."'" { g_curArgDefValue+=yytext; } |
|
139 <ReadFuncArgDef>\" { |
|
140 g_curArgDefValue+=*yytext; |
|
141 BEGIN( CopyArgString ); |
|
142 } |
|
143 <ReadFuncArgType>"("([^:)]+{B}*"::")*{B}*[&*]+{B}*/{ID} { |
|
144 // function pointer as argument |
|
145 g_curArgTypeName+=yytext; |
|
146 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); |
|
147 BEGIN( ReadFuncArgPtr ); |
|
148 } |
|
149 <ReadFuncArgPtr>{ID} { |
|
150 g_curArgName=yytext; |
|
151 } |
|
152 <ReadFuncArgPtr>")"{B}*"(" { // function pointer |
|
153 g_curArgTypeName+=yytext; |
|
154 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); |
|
155 g_readArgContext = ReadFuncArgType; |
|
156 g_copyArgValue=&g_curArgTypeName; |
|
157 g_argRoundCount=0; |
|
158 BEGIN( CopyArgRound2 ); |
|
159 } |
|
160 <ReadFuncArgPtr>")"/{B}*"[" { // pointer to fixed size array |
|
161 g_curArgTypeName+=yytext; |
|
162 g_curArgTypeName+=g_curArgName; |
|
163 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); |
|
164 BEGIN( ReadFuncArgType ); |
|
165 } |
|
166 <ReadFuncArgPtr>")" { // redundant braces detected / remove them |
|
167 int i=g_curArgTypeName.findRev('('),l=g_curArgTypeName.length(); |
|
168 if (i!=-1) |
|
169 g_curArgTypeName=g_curArgTypeName.left(i)+ |
|
170 g_curArgTypeName.right(l-i-1); |
|
171 g_curArgTypeName+=g_curArgName; |
|
172 BEGIN( ReadFuncArgType ); |
|
173 } |
|
174 <ReadFuncArgType>"<="|">="|"->"|">>"|"<<" { // handle operators in defargs |
|
175 g_curArgTypeName+=yytext; |
|
176 } |
|
177 <ReadFuncArgType,ReadFuncArgDef>[({<] { |
|
178 if (YY_START==ReadFuncArgType) |
|
179 { |
|
180 g_curArgTypeName+=*yytext; |
|
181 g_copyArgValue=&g_curArgTypeName; |
|
182 } |
|
183 else // YY_START==ReadFuncArgDef |
|
184 { |
|
185 g_curArgDefValue+=*yytext; |
|
186 g_copyArgValue=&g_curArgDefValue; |
|
187 } |
|
188 g_readArgContext = YY_START; |
|
189 if (*yytext=='(') |
|
190 { |
|
191 g_argRoundCount=0; |
|
192 BEGIN( CopyArgRound ); |
|
193 } |
|
194 else if (*yytext=='{') |
|
195 { |
|
196 g_argCurlyCount=0; |
|
197 BEGIN( CopyArgCurly ); |
|
198 } |
|
199 else // yytext=='<' |
|
200 { |
|
201 g_argSharpCount=0; |
|
202 BEGIN( CopyArgSharp ); |
|
203 } |
|
204 } |
|
205 <CopyArgRound,CopyArgRound2>"(" { |
|
206 g_argRoundCount++; |
|
207 *g_copyArgValue += *yytext; |
|
208 } |
|
209 <CopyArgRound,CopyArgRound2>")"({B}*{ID})* { |
|
210 *g_copyArgValue += yytext; |
|
211 if (g_argRoundCount>0) |
|
212 { |
|
213 g_argRoundCount--; |
|
214 } |
|
215 else |
|
216 { |
|
217 if (YY_START==CopyArgRound2) |
|
218 { |
|
219 *g_copyArgValue+=" "+g_curArgName; |
|
220 } |
|
221 BEGIN( g_readArgContext ); |
|
222 } |
|
223 } |
|
224 <CopyArgSharp>"<" { |
|
225 g_argSharpCount++; |
|
226 *g_copyArgValue += *yytext; |
|
227 } |
|
228 <CopyArgSharp>">" { |
|
229 *g_copyArgValue += *yytext; |
|
230 if (g_argSharpCount>0) g_argSharpCount--; |
|
231 else BEGIN( g_readArgContext ); |
|
232 } |
|
233 <CopyArgCurly>"{" { |
|
234 g_argCurlyCount++; |
|
235 *g_copyArgValue += *yytext; |
|
236 } |
|
237 <CopyArgSharp>"}" { |
|
238 *g_copyArgValue += *yytext; |
|
239 if (g_argCurlyCount>0) g_argCurlyCount--; |
|
240 else BEGIN( g_readArgContext ); |
|
241 } |
|
242 <CopyArgString>\\. { |
|
243 g_curArgDefValue+=yytext; |
|
244 } |
|
245 <CopyArgString>\" { |
|
246 g_curArgDefValue+=*yytext; |
|
247 BEGIN( ReadFuncArgDef ); |
|
248 } |
|
249 <ReadFuncArgType>"=" { |
|
250 BEGIN( ReadFuncArgDef ); |
|
251 } |
|
252 <ReadFuncArgType,ReadFuncArgDef>[,)>]{B}*("/*"[*!]|"//"[/!])"<" { |
|
253 g_lastDocContext=YY_START; |
|
254 g_lastDocChar=*yytext; |
|
255 QCString text=yytext; |
|
256 if (text.find("//")!=-1) |
|
257 BEGIN( ReadDocLine ); |
|
258 else |
|
259 BEGIN( ReadDocBlock ); |
|
260 } |
|
261 <ReadFuncArgType,ReadFuncArgDef>[,)>] { |
|
262 if (*yytext==')' && g_curArgTypeName.stripWhiteSpace().isEmpty()) |
|
263 { |
|
264 g_curArgTypeName+=*yytext; |
|
265 BEGIN(FuncQual); |
|
266 } |
|
267 else |
|
268 { |
|
269 g_curArgTypeName=removeRedundantWhiteSpace(g_curArgTypeName); |
|
270 g_curArgDefValue=g_curArgDefValue.stripWhiteSpace(); |
|
271 //printf("curArgType=`%s' curArgDefVal=`%s'\n",g_curArgTypeName.data(),g_curArgDefValue.data()); |
|
272 int l=g_curArgTypeName.length(); |
|
273 if (l>0) |
|
274 { |
|
275 int i=l-1; |
|
276 while (i>=0 && (isspace((uchar)g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='.')) i--; |
|
277 while (i>=0 && isId(g_curArgTypeName.at(i))) i--; |
|
278 //printf("g_curArgTypeName=`%s' i=%d\n",g_curArgTypeName.data(),i); |
|
279 Argument *a = new Argument; |
|
280 a->attrib = g_curArgAttrib.copy(); |
|
281 //printf("a->type=%s a->name=%s i=%d l=%d\n", |
|
282 // a->type.data(),a->name.data(),i,l); |
|
283 a->array.resize(0); |
|
284 if (i==l-1 && g_curArgTypeName.at(i)==')') // function argument |
|
285 { |
|
286 int bi=g_curArgTypeName.find('('); |
|
287 int fi=bi-1; |
|
288 //printf("func arg fi=%d\n",fi); |
|
289 while (fi>=0 && isId(g_curArgTypeName.at(fi))) fi--; |
|
290 if (fi>=0) |
|
291 { |
|
292 a->type = g_curArgTypeName.left(fi+1); |
|
293 a->name = g_curArgTypeName.mid(fi+1,bi-fi-1).stripWhiteSpace(); |
|
294 a->array = g_curArgTypeName.right(l-bi); |
|
295 } |
|
296 else |
|
297 { |
|
298 a->type = g_curArgTypeName; |
|
299 } |
|
300 } |
|
301 else if (i>=0 && g_curArgTypeName.at(i)!=':') |
|
302 { // type contains a name |
|
303 a->type = removeRedundantWhiteSpace(g_curArgTypeName.left(i+1)); |
|
304 a->name = g_curArgTypeName.right(l-i-1).stripWhiteSpace(); |
|
305 |
|
306 // if the type becomes a type specifier only then we make a mistake |
|
307 // and need to correct it to avoid seeing a nameless parameter |
|
308 // "struct A" as a parameter with type "struct" and name "A". |
|
309 int sv=0; |
|
310 if (a->type.left(6)=="const ") sv=6; |
|
311 else if (a->type.left(8)=="volatile ") sv=9; |
|
312 if (a->type.mid(sv)=="struct" || |
|
313 a->type.mid(sv)=="union" || |
|
314 a->type.mid(sv)=="class" || |
|
315 a->type.mid(sv)=="typename" || |
|
316 a->type=="const" || a->type=="volatile") |
|
317 { |
|
318 a->type = a->type + " " + a->name; |
|
319 a->name.resize(0); |
|
320 } |
|
321 } |
|
322 else // assume only the type was specified, try to determine name later |
|
323 { |
|
324 a->type = removeRedundantWhiteSpace(g_curArgTypeName); |
|
325 } |
|
326 a->array += removeRedundantWhiteSpace(g_curArgArray); |
|
327 //printf("array=%s\n",a->array.data()); |
|
328 int alen = a->array.length(); |
|
329 if (alen>2 && a->array.at(0)=='(' && |
|
330 a->array.at(alen-1)==')') // fix-up for int *(a[10]) |
|
331 { |
|
332 int i=a->array.find('[')-1; |
|
333 a->array = a->array.mid(1,alen-2); |
|
334 if (i>0 && a->name.isEmpty()) |
|
335 { |
|
336 a->name = a->array.left(i).stripWhiteSpace(); |
|
337 a->array = a->array.mid(i); |
|
338 } |
|
339 } |
|
340 a->defval = g_curArgDefValue.copy(); |
|
341 //printf("a->type=%s a->name=%s a->defval=\"%s\"\n",a->type.data(),a->name.data(),a->defval.data()); |
|
342 a->docs = g_curArgDocs.stripWhiteSpace(); |
|
343 //printf("Argument `%s' `%s' adding docs=`%s'\n",a->type.data(),a->name.data(),a->docs.data()); |
|
344 g_argList->append(a); |
|
345 } |
|
346 g_curArgAttrib.resize(0); |
|
347 g_curArgTypeName.resize(0); |
|
348 g_curArgDefValue.resize(0); |
|
349 g_curArgArray.resize(0); |
|
350 g_curArgDocs.resize(0); |
|
351 if (*yytext==')') |
|
352 { |
|
353 BEGIN(FuncQual); |
|
354 //printf(">>> end of argument list\n"); |
|
355 } |
|
356 else |
|
357 { |
|
358 BEGIN( ReadFuncArgType ); |
|
359 } |
|
360 } |
|
361 } |
|
362 <ReadFuncArgType,ReadFuncArgPtr>{ID} { |
|
363 QCString name=yytext; //resolveDefines(yytext); |
|
364 if (YY_START==ReadFuncArgType && g_curArgArray=="[]") // Java style array |
|
365 { |
|
366 g_curArgTypeName+=" []"; |
|
367 g_curArgArray.resize(0); |
|
368 } |
|
369 //printf("resolveName `%s'->`%s'\n",yytext,name.data()); |
|
370 g_curArgTypeName+=name; |
|
371 } |
|
372 <ReadFuncArgType,ReadFuncArgPtr>. { |
|
373 g_curArgTypeName+=*yytext; |
|
374 } |
|
375 |
|
376 <ReadFuncArgDef,CopyArgString>"->"|">="|">>" { |
|
377 g_curArgDefValue+=yytext; |
|
378 } |
|
379 <ReadFuncArgDef,CopyArgString>. { |
|
380 g_curArgDefValue+=*yytext; |
|
381 } |
|
382 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>{ID} { |
|
383 QCString name=yytext; //resolveDefines(yytext); |
|
384 *g_copyArgValue+=name; |
|
385 } |
|
386 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>. { |
|
387 *g_copyArgValue += *yytext; |
|
388 } |
|
389 <FuncQual>"const" { |
|
390 g_argList->constSpecifier=TRUE; |
|
391 } |
|
392 <FuncQual>"volatile" { |
|
393 g_argList->volatileSpecifier=TRUE; |
|
394 } |
|
395 <FuncQual>"="{B}*"0" { |
|
396 g_argList->pureSpecifier=TRUE; |
|
397 } |
|
398 <FuncQual>")"{B}*"["[^]]*"]" { // for functions returning a pointer to an array, |
|
399 // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]" |
|
400 g_extraTypeChars=yytext; |
|
401 } |
|
402 <ReadDocBlock>[^\*\n]+ { |
|
403 g_curArgDocs+=yytext; |
|
404 } |
|
405 <ReadDocLine>[^\n]+ { |
|
406 g_curArgDocs+=yytext; |
|
407 } |
|
408 <ReadDocBlock>"*/" { |
|
409 if (g_lastDocChar!=0) |
|
410 unput(g_lastDocChar); |
|
411 BEGIN(g_lastDocContext); |
|
412 } |
|
413 <ReadDocLine>\n { |
|
414 if (g_lastDocChar!=0) |
|
415 unput(g_lastDocChar); |
|
416 BEGIN(g_lastDocContext); |
|
417 } |
|
418 <ReadDocBlock>\n { |
|
419 g_curArgDocs+=*yytext; |
|
420 } |
|
421 <ReadDocBlock>. { |
|
422 g_curArgDocs+=*yytext; |
|
423 } |
|
424 <*>("/*"[*!]|"//"[/!])("<"?) { |
|
425 g_lastDocContext=YY_START; |
|
426 g_lastDocChar=0; |
|
427 if (yytext[1]=='/') |
|
428 BEGIN( ReadDocLine ); |
|
429 else |
|
430 BEGIN( ReadDocBlock ); |
|
431 } |
|
432 <*>\n |
|
433 <*>. |
|
434 |
|
435 %% |
|
436 |
|
437 /* ---------------------------------------------------------------------------- |
|
438 */ |
|
439 |
|
440 /*! Converts an argument string into an ArgumentList. |
|
441 * \param argsString the list of Arguments. |
|
442 * \param al a reference to resulting argument list pointer. |
|
443 */ |
|
444 |
|
445 void stringToArgumentList(const char *argsString,ArgumentList* al,QCString *extraTypeChars) |
|
446 { |
|
447 if (al==0) return; |
|
448 if (argsString==0) return; |
|
449 |
|
450 g_copyArgValue=0; |
|
451 g_curArgDocs.resize(0); |
|
452 g_curArgAttrib.resize(0); |
|
453 g_curArgArray.resize(0); |
|
454 g_extraTypeChars.resize(0); |
|
455 g_argRoundCount = 0; |
|
456 g_argSharpCount = 0; |
|
457 g_argCurlyCount = 0; |
|
458 g_lastDocChar = 0; |
|
459 |
|
460 g_inputString = argsString; |
|
461 g_inputPosition = 0; |
|
462 g_curArgTypeName.resize(0); |
|
463 g_curArgDefValue.resize(0); |
|
464 g_curArgName.resize(0); |
|
465 g_argList = al; |
|
466 defargsYYrestart( defargsYYin ); |
|
467 BEGIN( Start ); |
|
468 defargsYYlex(); |
|
469 if (extraTypeChars) *extraTypeChars=g_extraTypeChars; |
|
470 //printf("stringToArgumentList(%s) result=%s\n",argsString,argListToString(al).data()); |
|
471 } |
|
472 |
|
473 #if !defined(YY_FLEX_SUBMINOR_VERSION) |
|
474 extern "C" { // some bogus code to keep the compiler happy |
|
475 void defargsYYdummy() { yy_flex_realloc(0,0); } |
|
476 } |
|
477 #endif |
|
478 |