1 /******************************************************************************
5 * Copyright (C) 1997-2012 by Dimitri van Heesch.
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.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
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
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.
29 * Examples of input strings are:
31 * "(int a,int b) const"
32 * "(const char *s="hello world",int=5) = 0"
34 * "(char c,const char)"
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.
50 //#include <iostream.h>
58 #include "arguments.h"
60 #define YY_NEVER_INTERACTIVE 1
63 /* -----------------------------------------------------------------
66 static const char *g_inputString;
67 static int g_inputPosition;
68 static ArgumentList *g_argList;
69 static QCString *g_copyArgValue;
70 static QCString g_curArgTypeName;
71 static QCString g_curArgDefValue;
72 static QCString g_curArgName;
73 static QCString g_curArgDocs;
74 static QCString g_curArgAttrib;
75 static QCString g_curArgArray;
76 static QCString g_extraTypeChars;
77 static int g_argRoundCount;
78 static int g_argSharpCount;
79 static int g_argCurlyCount;
80 static int g_readArgContext;
81 static int g_lastDocContext;
82 static int g_lastDocChar;
83 static QCString g_delimiter;
85 /* -----------------------------------------------------------------
88 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
90 static int yyread(char *buf,int max_size)
93 while( c < max_size && g_inputString[g_inputPosition] )
95 *buf = g_inputString[g_inputPosition++] ;
104 ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
105 RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
106 RAWEND ")"[^ \t\(\)\\]{0,16}\"
128 <Start>[<(] { BEGIN(ReadFuncArgType); }
130 <ReadFuncArgType>{B}* {
131 g_curArgTypeName+=" ";
133 <ReadFuncArgType>"["[^\]]*"]" {
134 if (g_curArgTypeName.stripWhiteSpace().isEmpty())
136 g_curArgAttrib=yytext; // for M$-IDL
140 g_curArgArray+=yytext;
143 <ReadFuncArgDef>"'"\\[0-7]{1,3}"'" { g_curArgDefValue+=yytext; }
144 <ReadFuncArgDef>"'"\\."'" { g_curArgDefValue+=yytext; }
145 <ReadFuncArgDef>"'"."'" { g_curArgDefValue+=yytext; }
146 <ReadFuncArgDef>{RAWBEGIN} { g_curArgDefValue+=yytext;
147 QCString text=yytext;
148 int i=text.find('"');
149 g_delimiter = yytext+i+1;
150 g_delimiter=g_delimiter.left(g_delimiter.length()-1);
151 BEGIN( CopyRawString );
154 g_curArgDefValue+=*yytext;
155 BEGIN( CopyArgString );
157 <ReadFuncArgType>"("([^:)]+{B}*"::")*{B}*[&*\^]+{B}*/{ID} {
158 // function pointer as argument
159 g_curArgTypeName+=yytext;
160 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
161 BEGIN( ReadFuncArgPtr );
163 <ReadFuncArgPtr>{ID} {
166 <ReadFuncArgPtr>")"{B}*"(" { // function pointer
167 g_curArgTypeName+=yytext;
168 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
169 g_readArgContext = ReadFuncArgType;
170 g_copyArgValue=&g_curArgTypeName;
172 BEGIN( CopyArgRound2 );
174 <ReadFuncArgPtr>")"/{B}*"[" { // pointer to fixed size array
175 g_curArgTypeName+=yytext;
176 g_curArgTypeName+=g_curArgName;
177 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
178 BEGIN( ReadFuncArgType );
180 <ReadFuncArgPtr>")" { // redundant braces detected / remove them
181 int i=g_curArgTypeName.findRev('('),l=g_curArgTypeName.length();
183 g_curArgTypeName=g_curArgTypeName.left(i)+
184 g_curArgTypeName.right(l-i-1);
185 g_curArgTypeName+=g_curArgName;
186 BEGIN( ReadFuncArgType );
188 <ReadFuncArgType>"<="|">="|"->"|">>"|"<<" { // handle operators in defargs
189 g_curArgTypeName+=yytext;
191 <ReadFuncArgType,ReadFuncArgDef>[({<] {
192 if (YY_START==ReadFuncArgType)
194 g_curArgTypeName+=*yytext;
195 g_copyArgValue=&g_curArgTypeName;
197 else // YY_START==ReadFuncArgDef
199 g_curArgDefValue+=*yytext;
200 g_copyArgValue=&g_curArgDefValue;
202 g_readArgContext = YY_START;
206 BEGIN( CopyArgRound );
208 else if (*yytext=='{')
211 BEGIN( CopyArgCurly );
216 BEGIN( CopyArgSharp );
219 <CopyArgRound,CopyArgRound2>"(" {
221 *g_copyArgValue += *yytext;
223 <CopyArgRound,CopyArgRound2>")"({B}*{ID})* {
224 *g_copyArgValue += yytext;
225 if (g_argRoundCount>0)
231 if (YY_START==CopyArgRound2)
233 *g_copyArgValue+=" "+g_curArgName;
235 BEGIN( g_readArgContext );
238 <CopyArgRound>")"/{B}* {
239 *g_copyArgValue += *yytext;
240 if (g_argRoundCount>0) g_argRoundCount--;
241 else BEGIN( g_readArgContext );
245 *g_copyArgValue += *yytext;
248 *g_copyArgValue += *yytext;
249 if (g_argSharpCount>0) g_argSharpCount--;
250 else BEGIN( g_readArgContext );
254 *g_copyArgValue += *yytext;
257 *g_copyArgValue += *yytext;
258 if (g_argCurlyCount>0) g_argCurlyCount--;
259 else BEGIN( g_readArgContext );
262 g_curArgDefValue+=yytext;
264 <CopyRawString>{RAWEND} {
265 g_curArgDefValue+=yytext;
266 QCString delimiter = yytext+1;
267 delimiter=delimiter.left(delimiter.length()-1);
268 if (delimiter==g_delimiter)
270 BEGIN( ReadFuncArgDef );
274 g_curArgDefValue+=*yytext;
275 BEGIN( ReadFuncArgDef );
277 <ReadFuncArgType>"=" {
278 BEGIN( ReadFuncArgDef );
280 <ReadFuncArgType,ReadFuncArgDef>[,)>]{B}*("/*"[*!]|"//"[/!])"<" {
281 g_lastDocContext=YY_START;
282 g_lastDocChar=*yytext;
283 QCString text=yytext;
284 if (text.find("//")!=-1)
285 BEGIN( ReadDocLine );
287 BEGIN( ReadDocBlock );
289 <ReadFuncArgType,ReadFuncArgDef>[,)>] {
290 if (*yytext==')' && g_curArgTypeName.stripWhiteSpace().isEmpty())
292 g_curArgTypeName+=*yytext;
297 g_curArgTypeName=removeRedundantWhiteSpace(g_curArgTypeName);
298 g_curArgDefValue=g_curArgDefValue.stripWhiteSpace();
299 //printf("curArgType=`%s' curArgDefVal=`%s'\n",g_curArgTypeName.data(),g_curArgDefValue.data());
300 int l=g_curArgTypeName.length();
304 while (i>=0 && (isspace((uchar)g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='.')) i--;
305 while (i>=0 && (isId(g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='$')) i--;
306 Argument *a = new Argument;
307 a->attrib = g_curArgAttrib.copy();
308 //printf("a->type=%s a->name=%s i=%d l=%d\n",
309 // a->type.data(),a->name.data(),i,l);
311 if (i==l-1 && g_curArgTypeName.at(i)==')') // function argument
313 int bi=g_curArgTypeName.find('(');
315 //printf("func arg fi=%d\n",fi);
316 while (fi>=0 && isId(g_curArgTypeName.at(fi))) fi--;
319 a->type = g_curArgTypeName.left(fi+1);
320 a->name = g_curArgTypeName.mid(fi+1,bi-fi-1).stripWhiteSpace();
321 a->array = g_curArgTypeName.right(l-bi);
325 a->type = g_curArgTypeName;
328 else if (i>=0 && g_curArgTypeName.at(i)!=':')
329 { // type contains a name
330 a->type = removeRedundantWhiteSpace(g_curArgTypeName.left(i+1)).stripWhiteSpace();
331 a->name = g_curArgTypeName.right(l-i-1).stripWhiteSpace();
333 // if the type becomes a type specifier only then we make a mistake
334 // and need to correct it to avoid seeing a nameless parameter
335 // "struct A" as a parameter with type "struct" and name "A".
337 if (a->type.left(6)=="const ") sv=6;
338 else if (a->type.left(9)=="volatile ") sv=9;
340 if (a->type.mid(sv)=="struct" ||
341 a->type.mid(sv)=="union" ||
342 a->type.mid(sv)=="class" ||
343 a->type.mid(sv)=="typename" ||
348 a->type = a->type + " " + a->name;
351 //printf(" --> a->type='%s'\n",a->type.data());
353 else // assume only the type was specified, try to determine name later
355 a->type = removeRedundantWhiteSpace(g_curArgTypeName);
357 if (!a->type.isEmpty() && a->type.at(0)=='$') // typeless PHP name?
362 a->array += removeRedundantWhiteSpace(g_curArgArray);
363 //printf("array=%s\n",a->array.data());
364 int alen = a->array.length();
365 if (alen>2 && a->array.at(0)=='(' &&
366 a->array.at(alen-1)==')') // fix-up for int *(a[10])
368 int i=a->array.find('[')-1;
369 a->array = a->array.mid(1,alen-2);
370 if (i>0 && a->name.isEmpty())
372 a->name = a->array.left(i).stripWhiteSpace();
373 a->array = a->array.mid(i);
376 a->defval = g_curArgDefValue.copy();
377 //printf("a->type=%s a->name=%s a->defval=\"%s\"\n",a->type.data(),a->name.data(),a->defval.data());
378 a->docs = g_curArgDocs.stripWhiteSpace();
379 //printf("Argument `%s' `%s' adding docs=`%s'\n",a->type.data(),a->name.data(),a->docs.data());
380 g_argList->append(a);
382 g_curArgAttrib.resize(0);
383 g_curArgTypeName.resize(0);
384 g_curArgDefValue.resize(0);
385 g_curArgArray.resize(0);
386 g_curArgDocs.resize(0);
390 //printf(">>> end of argument list\n");
394 BEGIN( ReadFuncArgType );
398 <ReadFuncArgType,ReadFuncArgPtr>"$"?{ID} {
399 QCString name=yytext; //resolveDefines(yytext);
400 if (YY_START==ReadFuncArgType && g_curArgArray=="[]") // Java style array
402 g_curArgTypeName+=" []";
403 g_curArgArray.resize(0);
405 //printf("resolveName `%s'->`%s'\n",yytext,name.data());
406 g_curArgTypeName+=name;
408 <ReadFuncArgType,ReadFuncArgPtr>. {
409 g_curArgTypeName+=*yytext;
412 <ReadFuncArgDef,CopyArgString>"->"|">="|">>" {
413 g_curArgDefValue+=yytext;
415 <ReadFuncArgDef,CopyArgString,CopyRawString>. {
416 g_curArgDefValue+=*yytext;
418 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>{ID} {
419 QCString name=yytext; //resolveDefines(yytext);
420 *g_copyArgValue+=name;
422 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>. {
423 *g_copyArgValue += *yytext;
426 g_argList->constSpecifier=TRUE;
428 <FuncQual>"volatile" {
429 g_argList->volatileSpecifier=TRUE;
431 <FuncQual,TrailingReturn>"="{B}*"0" {
432 g_argList->pureSpecifier=TRUE;
435 <FuncQual>"->" { // C++11 trailing return type
436 g_argList->trailingReturnType=" -> ";
437 BEGIN(TrailingReturn);
439 <TrailingReturn>{B}/("final"|"override"){B}* {
444 g_argList->trailingReturnType+=yytext;
447 g_argList->trailingReturnType+=yytext;
449 <FuncQual>")"{B}*"["[^]]*"]" { // for functions returning a pointer to an array,
450 // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]"
451 g_extraTypeChars=yytext;
453 <ReadDocBlock>[^\*\n]+ {
454 g_curArgDocs+=yytext;
456 <ReadDocLine>[^\n]+ {
457 g_curArgDocs+=yytext;
460 if (g_lastDocChar!=0)
461 unput(g_lastDocChar);
462 BEGIN(g_lastDocContext);
465 if (g_lastDocChar!=0)
466 unput(g_lastDocChar);
467 BEGIN(g_lastDocContext);
470 g_curArgDocs+=*yytext;
473 g_curArgDocs+=*yytext;
475 <*>("/*"[*!]|"//"[/!])("<"?) {
476 g_lastDocContext=YY_START;
479 BEGIN( ReadDocLine );
481 BEGIN( ReadDocBlock );
488 /* ----------------------------------------------------------------------------
491 /*! Converts an argument string into an ArgumentList.
492 * \param[in] argsString the list of Arguments.
493 * \param[out] al a reference to resulting argument list pointer.
494 * \param[out] extraTypeChars point to string to which trailing characters
495 * for complex types are written to
498 void stringToArgumentList(const char *argsString,ArgumentList* al,QCString *extraTypeChars)
501 if (argsString==0) return;
504 g_curArgDocs.resize(0);
505 g_curArgAttrib.resize(0);
506 g_curArgArray.resize(0);
507 g_extraTypeChars.resize(0);
513 g_inputString = argsString;
515 g_curArgTypeName.resize(0);
516 g_curArgDefValue.resize(0);
517 g_curArgName.resize(0);
519 defargsYYrestart( defargsYYin );
522 if (extraTypeChars) *extraTypeChars=g_extraTypeChars;
523 //printf("stringToArgumentList(%s) result=%s\n",argsString,argListToString(al).data());
526 #if !defined(YY_FLEX_SUBMINOR_VERSION)
527 extern "C" { // some bogus code to keep the compiler happy
528 void defargsYYdummy() { yy_flex_realloc(0,0); }