1 /******************************************************************************
5 * Copyright (C) 1997-2015 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.
42 %option never-interactive
43 %option prefix="defargsYY"
51 //#include <iostream.h>
59 #include "arguments.h"
63 #define YY_NO_UNISTD_H 1
65 /* -----------------------------------------------------------------
68 static const char *g_inputString;
69 static int g_inputPosition;
70 static ArgumentList *g_argList;
71 static QCString *g_copyArgValue;
72 static QCString g_curArgTypeName;
73 static QCString g_curArgDefValue;
74 static QCString g_curArgName;
75 static QCString g_curArgDocs;
76 static QCString g_curArgAttrib;
77 static QCString g_curArgArray;
78 static QCString g_curTypeConstraint;
79 static QCString g_extraTypeChars;
80 static int g_argRoundCount;
81 static int g_argSharpCount;
82 static int g_argCurlyCount;
83 static int g_readArgContext;
84 static int g_lastDocContext;
85 static int g_lastDocChar;
86 static int g_lastExtendsContext;
87 static QCString g_delimiter;
89 /* -----------------------------------------------------------------
92 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
94 static int yyread(char *buf,int max_size)
97 while( c < max_size && g_inputString[g_inputPosition] )
99 *buf = g_inputString[g_inputPosition++] ;
108 ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
109 RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
110 RAWEND ")"[^ \t\(\)\\]{0,16}\"
127 %x ReadTypeConstraint
133 <Start>[<(] { BEGIN(ReadFuncArgType); }
135 <ReadFuncArgType>{B}* {
136 g_curArgTypeName+=" ";
138 <ReadFuncArgType>"["[^\]]*"]" {
139 if (g_curArgTypeName.stripWhiteSpace().isEmpty())
141 g_curArgAttrib=yytext; // for M$-IDL
145 g_curArgArray+=yytext;
148 <ReadFuncArgDef>"'"\\[0-7]{1,3}"'" { g_curArgDefValue+=yytext; }
149 <ReadFuncArgDef>"'"\\."'" { g_curArgDefValue+=yytext; }
150 <ReadFuncArgDef>"'"."'" { g_curArgDefValue+=yytext; }
151 <ReadFuncArgDef>{RAWBEGIN} { g_curArgDefValue+=yytext;
152 QCString text=yytext;
153 int i=text.find('"');
154 g_delimiter = yytext+i+1;
155 g_delimiter=g_delimiter.left(g_delimiter.length()-1);
156 BEGIN( CopyRawString );
159 g_curArgDefValue+=*yytext;
160 BEGIN( CopyArgString );
162 <ReadFuncArgType>"("([^:)]+{B}*"::")*{B}*[&*\^]+{B}*/{ID} {
163 // function pointer as argument
164 g_curArgTypeName+=yytext;
165 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
166 BEGIN( ReadFuncArgPtr );
168 <ReadFuncArgPtr>{ID} {
171 <ReadFuncArgPtr>")"{B}*"(" { // function pointer
172 g_curArgTypeName+=yytext;
173 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
174 g_readArgContext = ReadFuncArgType;
175 g_copyArgValue=&g_curArgTypeName;
177 BEGIN( CopyArgRound2 );
179 <ReadFuncArgPtr>")"/{B}*"[" { // pointer to fixed size array
180 g_curArgTypeName+=yytext;
181 g_curArgTypeName+=g_curArgName;
182 //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
183 BEGIN( ReadFuncArgType );
185 <ReadFuncArgPtr>")" { // redundant braces detected / remove them
186 int i=g_curArgTypeName.findRev('('),l=g_curArgTypeName.length();
188 g_curArgTypeName=g_curArgTypeName.left(i)+
189 g_curArgTypeName.right(l-i-1);
190 g_curArgTypeName+=g_curArgName;
191 BEGIN( ReadFuncArgType );
193 <ReadFuncArgType>"<="|">="|"->"|">>"|"<<" { // handle operators in defargs
194 g_curArgTypeName+=yytext;
196 <ReadFuncArgType,ReadFuncArgDef>[({<] {
197 if (YY_START==ReadFuncArgType)
199 g_curArgTypeName+=*yytext;
200 g_copyArgValue=&g_curArgTypeName;
202 else // YY_START==ReadFuncArgDef
204 g_curArgDefValue+=*yytext;
205 g_copyArgValue=&g_curArgDefValue;
207 g_readArgContext = YY_START;
211 BEGIN( CopyArgRound );
213 else if (*yytext=='{')
216 BEGIN( CopyArgCurly );
222 BEGIN( CopyArgSharp );
225 <CopyArgRound,CopyArgRound2>"(" {
227 *g_copyArgValue += *yytext;
229 <CopyArgRound,CopyArgRound2>")"({B}*{ID})* {
230 *g_copyArgValue += yytext;
231 if (g_argRoundCount>0)
237 if (YY_START==CopyArgRound2)
239 *g_copyArgValue+=" "+g_curArgName;
241 BEGIN( g_readArgContext );
244 <CopyArgRound>")"/{B}* {
245 *g_copyArgValue += *yytext;
246 if (g_argRoundCount>0) g_argRoundCount--;
247 else BEGIN( g_readArgContext );
250 if (g_argRoundCount>0)
252 *g_copyArgValue += yytext;
259 <CopyArgSharp>">>)" { // combined token (see bug 790320)
260 *g_copyArgValue += yytext;
261 if (g_argSharpCount>0) g_argSharpCount--;
262 else BEGIN( g_readArgContext );
263 if (g_argSharpCount>0) g_argSharpCount--;
264 else BEGIN( g_readArgContext );
268 if (g_argRoundCount>0)
270 *g_copyArgValue += yytext;
279 *g_copyArgValue += *yytext;
282 *g_copyArgValue += *yytext;
283 if (g_argSharpCount>0) g_argSharpCount--;
284 else BEGIN( g_readArgContext );
288 *g_copyArgValue += *yytext;
292 *g_copyArgValue += *yytext;
296 *g_copyArgValue += *yytext;
299 *g_copyArgValue += *yytext;
300 if (g_argCurlyCount>0) g_argCurlyCount--;
301 else BEGIN( g_readArgContext );
304 g_curArgDefValue+=yytext;
306 <CopyRawString>{RAWEND} {
307 g_curArgDefValue+=yytext;
308 QCString delimiter = yytext+1;
309 delimiter=delimiter.left(delimiter.length()-1);
310 if (delimiter==g_delimiter)
312 BEGIN( ReadFuncArgDef );
316 g_curArgDefValue+=*yytext;
317 BEGIN( ReadFuncArgDef );
319 <ReadFuncArgType>"=" {
320 BEGIN( ReadFuncArgDef );
322 <ReadFuncArgType,ReadFuncArgDef>[,)>]{B}*("/*"[*!]|"//"[/!])"<" {
323 g_lastDocContext=YY_START;
324 g_lastDocChar=*yytext;
325 QCString text=yytext;
326 if (text.find("//")!=-1)
327 BEGIN( ReadDocLine );
329 BEGIN( ReadDocBlock );
331 <ReadFuncArgType,ReadFuncArgDef>[,)>] {
332 if (*yytext==')' && g_curArgTypeName.stripWhiteSpace().isEmpty())
334 g_curArgTypeName+=*yytext;
339 g_curArgTypeName=removeRedundantWhiteSpace(g_curArgTypeName);
340 g_curArgDefValue=g_curArgDefValue.stripWhiteSpace();
341 //printf("curArgType=`%s' curArgDefVal=`%s'\n",g_curArgTypeName.data(),g_curArgDefValue.data());
342 int l=g_curArgTypeName.length();
346 while (i>=0 && (isspace((uchar)g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='.')) i--;
347 while (i>=0 && (isId(g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='$')) i--;
348 Argument *a = new Argument;
349 a->attrib = g_curArgAttrib.copy();
350 a->typeConstraint = g_curTypeConstraint.stripWhiteSpace();
351 //printf("a->type=%s a->name=%s i=%d l=%d\n",
352 // a->type.data(),a->name.data(),i,l);
354 if (i==l-1 && g_curArgTypeName.at(i)==')') // function argument
356 int bi=g_curArgTypeName.find('(');
358 //printf("func arg fi=%d\n",fi);
359 while (fi>=0 && (isId(g_curArgTypeName.at(fi)) || g_curArgTypeName.at(fi)==':')) fi--;
362 a->type = g_curArgTypeName.left(fi+1);
363 a->name = g_curArgTypeName.mid(fi+1,bi-fi-1).stripWhiteSpace();
364 a->array = g_curArgTypeName.right(l-bi);
368 a->type = g_curArgTypeName;
371 else if (i>=0 && g_curArgTypeName.at(i)!=':')
372 { // type contains a name
373 a->type = removeRedundantWhiteSpace(g_curArgTypeName.left(i+1)).stripWhiteSpace();
374 a->name = g_curArgTypeName.right(l-i-1).stripWhiteSpace();
376 // if the type becomes a type specifier only then we make a mistake
377 // and need to correct it to avoid seeing a nameless parameter
378 // "struct A" as a parameter with type "struct" and name "A".
380 if (a->type.left(6)=="const ") sv=6;
381 else if (a->type.left(9)=="volatile ") sv=9;
383 if (a->type.mid(sv)=="struct" ||
384 a->type.mid(sv)=="union" ||
385 a->type.mid(sv)=="class" ||
386 a->type.mid(sv)=="typename" ||
391 a->type = a->type + " " + a->name;
394 //printf(" --> a->type='%s' a->name='%s'\n",a->type.data(),a->name.data());
396 else // assume only the type was specified, try to determine name later
398 a->type = removeRedundantWhiteSpace(g_curArgTypeName);
400 if (!a->type.isEmpty() && a->type.at(0)=='$') // typeless PHP name?
405 a->array += removeRedundantWhiteSpace(g_curArgArray);
406 //printf("array=%s\n",a->array.data());
407 int alen = a->array.length();
408 if (alen>2 && a->array.at(0)=='(' &&
409 a->array.at(alen-1)==')') // fix-up for int *(a[10])
411 int i=a->array.find('[')-1;
412 a->array = a->array.mid(1,alen-2);
413 if (i>0 && a->name.isEmpty())
415 a->name = a->array.left(i).stripWhiteSpace();
416 a->array = a->array.mid(i);
419 a->defval = g_curArgDefValue.copy();
420 //printf("a->type=%s a->name=%s a->defval=\"%s\"\n",a->type.data(),a->name.data(),a->defval.data());
421 a->docs = g_curArgDocs.stripWhiteSpace();
422 //printf("Argument `%s' `%s' adding docs=`%s'\n",a->type.data(),a->name.data(),a->docs.data());
423 g_argList->append(a);
425 g_curArgAttrib.resize(0);
426 g_curArgTypeName.resize(0);
427 g_curArgDefValue.resize(0);
428 g_curArgArray.resize(0);
429 g_curArgDocs.resize(0);
430 g_curTypeConstraint.resize(0);
434 //printf(">>> end of argument list\n");
438 BEGIN( ReadFuncArgType );
442 <ReadFuncArgType,ReadFuncArgPtr>"extends" {
443 g_curTypeConstraint.resize(0);
444 g_lastExtendsContext=YY_START;
445 BEGIN(ReadTypeConstraint);
447 <ReadFuncArgType,ReadFuncArgPtr>"$"?{ID} {
448 QCString name=yytext; //resolveDefines(yytext);
449 if (YY_START==ReadFuncArgType && g_curArgArray=="[]") // Java style array
451 g_curArgTypeName+=" []";
452 g_curArgArray.resize(0);
454 //printf("resolveName `%s'->`%s'\n",yytext,name.data());
455 g_curArgTypeName+=name;
457 <ReadFuncArgType,ReadFuncArgPtr>. {
458 g_curArgTypeName+=*yytext;
461 <ReadFuncArgDef,CopyArgString>"<="|"->"|">="|">>"|"<<" {
462 g_curArgDefValue+=yytext;
464 <ReadFuncArgDef,CopyArgString,CopyRawString>. {
465 g_curArgDefValue+=*yytext;
467 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>{ID} {
468 QCString name=yytext; //resolveDefines(yytext);
469 *g_copyArgValue+=name;
471 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>. {
472 *g_copyArgValue += *yytext;
474 <ReadTypeConstraint>[,)>] {
476 BEGIN(g_lastExtendsContext);
478 <ReadTypeConstraint>. {
479 g_curTypeConstraint+=yytext;
481 <ReadTypeConstraint>\n {
482 g_curTypeConstraint+=' ';
485 g_argList->constSpecifier=TRUE;
487 <FuncQual>"volatile" {
488 g_argList->volatileSpecifier=TRUE;
491 g_argList->refQualifier=RefQualifierLValue;
494 g_argList->refQualifier=RefQualifierRValue;
496 <FuncQual,TrailingReturn>"="{B}*"0" {
497 g_argList->pureSpecifier=TRUE;
500 <FuncQual>"->" { // C++11 trailing return type
501 g_argList->trailingReturnType=" -> ";
502 BEGIN(TrailingReturn);
504 <TrailingReturn>{B}/("final"|"override"){B}* {
509 g_argList->trailingReturnType+=yytext;
512 g_argList->trailingReturnType+=yytext;
514 <FuncQual>")"{B}*"["[^]]*"]" { // for functions returning a pointer to an array,
515 // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]"
516 g_extraTypeChars=yytext;
518 <ReadDocBlock>[^\*\n]+ {
519 g_curArgDocs+=yytext;
521 <ReadDocLine>[^\n]+ {
522 g_curArgDocs+=yytext;
525 if (g_lastDocChar!=0)
526 unput(g_lastDocChar);
527 BEGIN(g_lastDocContext);
530 if (g_lastDocChar!=0)
531 unput(g_lastDocChar);
532 BEGIN(g_lastDocContext);
535 g_curArgDocs+=*yytext;
538 g_curArgDocs+=*yytext;
540 <*>("/*"[*!]|"//"[/!])("<"?) {
541 g_lastDocContext=YY_START;
544 BEGIN( ReadDocLine );
546 BEGIN( ReadDocBlock );
553 /* ----------------------------------------------------------------------------
556 /*! Converts an argument string into an ArgumentList.
557 * \param[in] argsString the list of Arguments.
558 * \param[out] al a reference to resulting argument list pointer.
559 * \param[out] extraTypeChars point to string to which trailing characters
560 * for complex types are written to
563 void stringToArgumentList(const char *argsString,ArgumentList* al,QCString *extraTypeChars)
566 if (argsString==0) return;
567 printlex(yy_flex_debug, TRUE, __FILE__, NULL);
570 g_curArgDocs.resize(0);
571 g_curArgAttrib.resize(0);
572 g_curArgArray.resize(0);
573 g_curTypeConstraint.resize(0);
574 g_extraTypeChars.resize(0);
580 g_inputString = argsString;
582 g_curArgTypeName.resize(0);
583 g_curArgDefValue.resize(0);
584 g_curArgName.resize(0);
586 defargsYYrestart( defargsYYin );
589 if (extraTypeChars) *extraTypeChars=g_extraTypeChars;
590 //printf("stringToArgumentList(%s) result=%s\n",argsString,argListToString(al).data());
591 printlex(yy_flex_debug, FALSE, __FILE__, NULL);
594 #if !defined(YY_FLEX_SUBMINOR_VERSION)
595 extern "C" { // some bogus code to keep the compiler happy
596 void defargsYYdummy() { yy_flex_realloc(0,0); }