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"
45 %option extra-type="struct defargsYY_state *"
48 // forward declare yyscan_t to improve type safety
49 #define YY_TYPEDEF_YY_SCANNER_T
51 typedef yyguts_t *yyscan_t;
60 //#include <iostream.h>
67 #include "arguments.h"
71 #define YY_NO_UNISTD_H 1
73 #define USE_STATE2STRING 0
75 /* -----------------------------------------------------------------
78 struct defargsYY_state
80 defargsYY_state(const char *inStr,std::unique_ptr<ArgumentList> &al,SrcLangExt l)
81 : inputString(inStr), argList(al), lang(l) {}
82 const char *inputString;
83 std::unique_ptr<ArgumentList> &argList;
85 int inputPosition = 0;
86 QCString *copyArgValue = 0;
87 QCString curArgTypeName;
88 QCString curArgDefValue;
91 QCString curArgAttrib;
93 QCString curTypeConstraint;
94 QCString extraTypeChars;
95 int argRoundCount = 0;
96 int argSquareCount = 0;
97 int argSharpCount = 0;
98 int argCurlyCount = 0;
99 int readArgContext = 0;
100 int lastDocContext = 0;
102 int lastExtendsContext = 0;
107 static const char *stateToString(int state);
110 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
111 static bool nameIsActuallyPartOfType(QCString &name);
113 /* -----------------------------------------------------------------
116 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
122 ID [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
123 RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
124 RAWEND ")"[^ \t\(\)\\]{0,16}\"
149 %x ReadTypeConstraint
155 <Start>[<(] { BEGIN(ReadFuncArgType); }
157 <ReadFuncArgType>{B}* {
158 yyextra->curArgTypeName+=" ";
160 <ReadFuncArgType>"["[^\]]*"]" {
161 if (yyextra->curArgTypeName.stripWhiteSpace().isEmpty())
163 yyextra->curArgAttrib=yytext; // for M$-IDL
167 yyextra->curArgArray+=yytext;
170 <ReadFuncArgDef>"'"\\[0-7]{1,3}"'" { yyextra->curArgDefValue+=yytext; }
171 <ReadFuncArgDef>"'"\\."'" { yyextra->curArgDefValue+=yytext; }
172 <ReadFuncArgDef>"'"."'" { yyextra->curArgDefValue+=yytext; }
173 <ReadFuncArgDef>{RAWBEGIN} { yyextra->curArgDefValue+=yytext;
174 QCString text(yytext);
175 int i=text.find('"');
176 yyextra->delimiter = yytext+i+1;
177 yyextra->delimiter=yyextra->delimiter.left(yyextra->delimiter.length()-1);
178 BEGIN( CopyRawString );
181 yyextra->curArgDefValue+=*yytext;
182 BEGIN( CopyArgString );
184 <ReadFuncArgType>"("([^:)]+{B}*"::")*{B}*[&*\^]+{Bopt}/{ID} {
185 // function pointer as argument
186 yyextra->curArgTypeName+=yytext;
187 //yyextra->curArgTypeName=yyextra->curArgTypeName.simplifyWhiteSpace();
188 BEGIN( ReadFuncArgPtr );
190 <ReadFuncArgPtr>{ID} {
191 yyextra->curArgName=yytext;
193 <ReadFuncArgPtr>")"{B}*"(" { // function pointer
194 yyextra->curArgTypeName+=yytext;
195 //yyextra->curArgTypeName=yyextra->curArgTypeName.simplifyWhiteSpace();
196 yyextra->readArgContext = ReadFuncArgType;
197 yyextra->copyArgValue=&yyextra->curArgTypeName;
198 yyextra->argRoundCount=0;
199 BEGIN( CopyArgRound2 );
201 <ReadFuncArgPtr>")"/{B}*"[" { // pointer to fixed size array
202 yyextra->curArgTypeName+=yytext;
203 yyextra->curArgTypeName+=yyextra->curArgName;
204 //yyextra->curArgTypeName=yyextra->curArgTypeName.simplifyWhiteSpace();
205 BEGIN( ReadFuncArgType );
207 <ReadFuncArgPtr>")" { // redundant braces detected / remove them
208 int i=yyextra->curArgTypeName.findRev('('),l=yyextra->curArgTypeName.length();
210 yyextra->curArgTypeName=yyextra->curArgTypeName.left(i)+
211 yyextra->curArgTypeName.right(l-i-1);
212 yyextra->curArgTypeName+=yyextra->curArgName;
213 BEGIN( ReadFuncArgType );
215 <ReadFuncArgType>"<="|">="|"->"|">>"|"<<" { // handle operators in defargs
216 yyextra->curArgTypeName+=yytext;
218 <ReadFuncArgType,ReadFuncArgDef>[({<\[] {
219 if (YY_START==ReadFuncArgType)
221 yyextra->curArgTypeName+=*yytext;
222 yyextra->copyArgValue=&yyextra->curArgTypeName;
224 else // YY_START==ReadFuncArgDef
226 yyextra->curArgDefValue+=*yytext;
227 yyextra->copyArgValue=&yyextra->curArgDefValue;
229 yyextra->readArgContext = YY_START;
232 yyextra->argRoundCount=0;
233 BEGIN( CopyArgRound );
235 else if (*yytext=='[')
237 yyextra->argSquareCount=0;
238 BEGIN( CopyArgSquare );
240 else if (*yytext=='{')
242 yyextra->argCurlyCount=0;
243 BEGIN( CopyArgCurly );
247 yyextra->argSharpCount=0;
248 yyextra->argRoundCount=0;
249 BEGIN( CopyArgSharp );
252 <CopyArgRound,CopyArgRound2>"(" {
253 yyextra->argRoundCount++;
254 *yyextra->copyArgValue += *yytext;
256 <CopyArgRound,CopyArgRound2>")"({B}*{ID})* {
257 *yyextra->copyArgValue += yytext;
258 if (yyextra->argRoundCount>0)
260 yyextra->argRoundCount--;
264 if (YY_START==CopyArgRound2)
266 *yyextra->copyArgValue+=" "+yyextra->curArgName;
268 BEGIN( yyextra->readArgContext );
271 <CopyArgRound>")"/{B}* {
272 *yyextra->copyArgValue += *yytext;
273 if (yyextra->argRoundCount>0) yyextra->argRoundCount--;
274 else BEGIN( yyextra->readArgContext );
277 yyextra->argSquareCount++;
278 *yyextra->copyArgValue += *yytext;
280 <CopyArgSquare>"]"({B}*{ID})* {
281 *yyextra->copyArgValue += yytext;
282 if (yyextra->argSquareCount>0)
284 yyextra->argRoundCount--;
288 BEGIN( yyextra->readArgContext );
291 <CopyArgSquare>"]"/{B}* {
292 *yyextra->copyArgValue += *yytext;
293 if (yyextra->argSquareCount>0) yyextra->argSquareCount--;
294 else BEGIN( yyextra->readArgContext );
297 if (yyextra->argRoundCount>0)
299 // for e.g. < typename A = (i<<3) >
300 *yyextra->copyArgValue += yytext;
308 if (yyextra->argRoundCount>0)
310 // for e.g. < typename A = (i>>3) >
311 *yyextra->copyArgValue += yytext;
319 // don't count < inside (, e.g. for things like: < typename A=(i<6) >
320 if (yyextra->argRoundCount==0) yyextra->argSharpCount++;
321 *yyextra->copyArgValue += *yytext;
324 *yyextra->copyArgValue += *yytext;
325 if (yyextra->argRoundCount>0 && yyextra->argSharpCount==0)
327 // don't count > inside )
331 if (yyextra->argSharpCount>0)
333 yyextra->argSharpCount--;
337 BEGIN( yyextra->readArgContext );
342 yyextra->argRoundCount++;
343 *yyextra->copyArgValue += *yytext;
346 yyextra->argRoundCount--;
347 *yyextra->copyArgValue += *yytext;
350 yyextra->argCurlyCount++;
351 *yyextra->copyArgValue += *yytext;
354 *yyextra->copyArgValue += *yytext;
355 if (yyextra->argCurlyCount>0) yyextra->argCurlyCount--;
356 else BEGIN( yyextra->readArgContext );
359 yyextra->curArgDefValue+=yytext;
361 <CopyRawString>{RAWEND} {
362 yyextra->curArgDefValue+=yytext;
363 QCString delimiter(yytext+1);
364 delimiter=delimiter.left(delimiter.length()-1);
365 if (delimiter==yyextra->delimiter)
367 BEGIN( ReadFuncArgDef );
371 yyextra->curArgDefValue+=*yytext;
372 BEGIN( ReadFuncArgDef );
374 <ReadFuncArgType>"=" {
375 BEGIN( ReadFuncArgDef );
377 <ReadFuncArgType,ReadFuncArgDef>[,)>]{B}*({CCS}[*!]|{CPPC}[/!])"<" {
378 yyextra->lastDocContext=YY_START;
379 yyextra->lastDocChar=*yytext;
380 QCString text(yytext);
381 if (text.find("//")!=-1)
382 BEGIN( ReadDocLine );
384 BEGIN( ReadDocBlock );
386 <ReadFuncArgType,ReadFuncArgDef>[,)>] {
387 if (*yytext==')' && yyextra->curArgTypeName.stripWhiteSpace().isEmpty())
389 yyextra->curArgTypeName+=*yytext;
394 yyextra->curArgTypeName=removeRedundantWhiteSpace(yyextra->curArgTypeName);
395 yyextra->curArgDefValue=yyextra->curArgDefValue.stripWhiteSpace();
396 //printf("curArgType='%s' curArgDefVal='%s'\n",qPrint(yyextra->curArgTypeName),qPrint(yyextra->curArgDefValue));
397 int l=yyextra->curArgTypeName.length();
401 while (i>=0 && (isspace((uchar)yyextra->curArgTypeName.at(i)) || yyextra->curArgTypeName.at(i)=='.')) i--;
402 while (i>=0 && (isId(yyextra->curArgTypeName.at(i)) || yyextra->curArgTypeName.at(i)=='$')) i--;
404 a.attrib = yyextra->curArgAttrib;
405 a.typeConstraint = yyextra->curTypeConstraint.stripWhiteSpace();
406 //printf("a->type=%s a->name=%s i=%d l=%d\n",
407 // qPrint(a->type),qPrint(a->name),i,l);
409 if (i==l-1 && yyextra->curArgTypeName.at(i)==')') // function argument
411 int bi=yyextra->curArgTypeName.find('(');
413 //printf("func arg fi=%d\n",fi);
414 while (fi>=0 && (isId(yyextra->curArgTypeName.at(fi)) || yyextra->curArgTypeName.at(fi)==':')) fi--;
417 a.type = yyextra->curArgTypeName.left(fi+1);
418 a.name = yyextra->curArgTypeName.mid(fi+1,bi-fi-1).stripWhiteSpace();
419 a.array = yyextra->curArgTypeName.right(l-bi);
423 a.type = yyextra->curArgTypeName;
426 else if (i>=0 && yyextra->curArgTypeName.at(i)!=':')
427 { // type contains a name
428 a.type = removeRedundantWhiteSpace(yyextra->curArgTypeName.left(i+1)).stripWhiteSpace();
429 a.name = yyextra->curArgTypeName.right(l-i-1).stripWhiteSpace();
431 // if the type becomes a type specifier only then we make a mistake
432 // and need to correct it to avoid seeing a nameless parameter
433 // "struct A" as a parameter with type "struct" and name "A".
435 if (a.type.left(6)=="const ") sv=6;
436 else if (a.type.left(9)=="volatile ") sv=9;
438 if (a.type.mid(sv)=="struct" ||
439 a.type.mid(sv)=="union" ||
440 a.type.mid(sv)=="class" ||
441 a.type.mid(sv)=="typename" ||
442 nameIsActuallyPartOfType(a.name)
445 a.type = a.type + " " + a.name;
448 //printf(" --> a->type='%s' a->name='%s'\n",qPrint(a->type),qPrint(a->name));
450 else // assume only the type was specified, try to determine name later
452 a.type = removeRedundantWhiteSpace(yyextra->curArgTypeName);
454 if (!a.type.isEmpty() && a.type.at(0)=='$') // typeless PHP name?
459 a.array += removeRedundantWhiteSpace(yyextra->curArgArray);
460 //printf("array=%s\n",qPrint(a->array));
461 int alen = a.array.length();
462 if (alen>2 && a.array.at(0)=='(' &&
463 a.array.at(alen-1)==')') // fix-up for int *(a[10])
465 i=a.array.find('[')-1;
466 a.array = a.array.mid(1,alen-2);
467 if (i>0 && a.name.isEmpty())
469 a.name = a.array.left(i).stripWhiteSpace();
470 a.array = a.array.mid(i);
473 a.defval = yyextra->curArgDefValue;
474 //printf("a->type=%s a->name=%s a->defval=\"%s\"\n",qPrint(a->type),qPrint(a->name),qPrint(a->defval));
475 a.docs = yyextra->curArgDocs.stripWhiteSpace();
476 //printf("Argument '%s' '%s' adding docs='%s'\n",qPrint(a->type),qPrint(a->name),qPrint(a->docs));
477 yyextra->argList->push_back(a);
479 yyextra->curArgAttrib.resize(0);
480 yyextra->curArgTypeName.resize(0);
481 yyextra->curArgDefValue.resize(0);
482 yyextra->curArgArray.resize(0);
483 yyextra->curArgDocs.resize(0);
484 yyextra->curTypeConstraint.resize(0);
488 //printf(">>> end of argument list\n");
492 BEGIN( ReadFuncArgType );
496 <ReadFuncArgType,ReadFuncArgPtr>"extends" {
497 if (yyextra->lang!=SrcLangExt_Java)
503 yyextra->curTypeConstraint.resize(0);
504 yyextra->lastExtendsContext=YY_START;
505 BEGIN(ReadTypeConstraint);
508 <ReadFuncArgType,ReadFuncArgPtr>"$"?{ID} {
509 QCString name(yytext);
510 if (YY_START==ReadFuncArgType && yyextra->curArgArray=="[]") // Java style array
512 yyextra->curArgTypeName+=" []";
513 yyextra->curArgArray.resize(0);
515 //printf("resolveName '%s'->'%s'\n",yytext,qPrint(name));
516 yyextra->curArgTypeName+=name;
518 <ReadFuncArgType,ReadFuncArgPtr>. {
519 yyextra->curArgTypeName+=*yytext;
522 <ReadFuncArgDef,CopyArgString>"<="|"->"|">="|">>"|"<<" {
523 yyextra->curArgDefValue+=yytext;
525 <ReadFuncArgDef,CopyArgString,CopyRawString>. {
526 yyextra->curArgDefValue+=*yytext;
528 <CopyArgRound,CopyArgRound2,CopyArgSquare,CopyArgSharp,CopyArgCurly>{ID} {
529 *yyextra->copyArgValue+=yytext;
531 <CopyArgRound,CopyArgRound2,CopyArgSquare,CopyArgSharp,CopyArgCurly>. {
532 *yyextra->copyArgValue += *yytext;
534 <ReadTypeConstraint>[,)>] {
536 BEGIN(yyextra->lastExtendsContext);
538 <ReadTypeConstraint>. {
539 yyextra->curTypeConstraint+=yytext;
541 <ReadTypeConstraint>\n {
542 yyextra->curTypeConstraint+=' ';
545 yyextra->argList->setConstSpecifier(TRUE);
547 <FuncQual>"volatile" {
548 yyextra->argList->setVolatileSpecifier(TRUE);
550 <FuncQual>"override" {
553 yyextra->argList->setRefQualifier(RefQualifierLValue);
556 yyextra->argList->setRefQualifier(RefQualifierRValue);
558 <FuncQual,TrailingReturn>"="{B}*"0" {
559 yyextra->argList->setPureSpecifier(TRUE);
562 <FuncQual>"->" { // C++11 trailing return type
563 yyextra->argList->setTrailingReturnType(QCString(" -> "));
564 BEGIN(TrailingReturn);
566 <TrailingReturn>{B}/("final"|"override"){B}* {
571 yyextra->argList->setTrailingReturnType(yyextra->argList->trailingReturnType()+yytext);
574 yyextra->argList->setTrailingReturnType(yyextra->argList->trailingReturnType()+yytext);
576 <FuncQual>")"{B}*"["[^]]*"]" { // for functions returning a pointer to an array,
577 // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]"
578 yyextra->extraTypeChars=yytext;
580 <ReadDocBlock>[^\*\n]+ {
581 yyextra->curArgDocs+=yytext;
583 <ReadDocLine>[^\n]+ {
584 yyextra->curArgDocs+=yytext;
586 <ReadDocBlock>{CCE} {
587 if (yyextra->lastDocChar!=0)
588 unput(yyextra->lastDocChar);
589 BEGIN(yyextra->lastDocContext);
592 if (yyextra->lastDocChar!=0)
593 unput(yyextra->lastDocChar);
594 BEGIN(yyextra->lastDocContext);
597 yyextra->curArgDocs+=*yytext;
600 yyextra->curArgDocs+=*yytext;
602 <*>({CCS}[*!]|{CPPC}[/!])("<"?) {
603 yyextra->lastDocContext=YY_START;
604 yyextra->lastDocChar=0;
606 BEGIN( ReadDocLine );
608 BEGIN( ReadDocBlock );
615 /* ----------------------------------------------------------------------------
618 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
620 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
622 while( c < max_size && yyextra->inputString[yyextra->inputPosition] )
624 *buf = yyextra->inputString[yyextra->inputPosition++] ;
631 The following code is generated using 'gperf keywords.txt'
632 where keywords.txt has the following content
634 ---------------------------------
635 %define class-name KeywordHash
636 %define lookup-function-name find
669 ---------------------------------
671 //--- begin gperf generated code ----------------------------------------------------------
673 #define TOTAL_KEYWORDS 28
674 #define MIN_WORD_LENGTH 3
675 #define MAX_WORD_LENGTH 9
676 #define MIN_HASH_VALUE 3
677 #define MAX_HASH_VALUE 48
678 /* maximum key range = 46, duplicates = 0 */
683 static inline unsigned int hash (const char *str, unsigned int len);
685 static const char *find (const char *str, unsigned int len);
689 KeywordHash::hash (const char *str, unsigned int len)
691 static const unsigned char asso_values[] =
693 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
694 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
695 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
696 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
697 49, 49, 49, 49, 49, 49, 49, 49, 49, 5,
698 5, 30, 0, 49, 25, 49, 10, 49, 49, 49,
699 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
700 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
701 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
702 49, 49, 49, 49, 49, 0, 49, 0, 5, 49,
703 15, 0, 49, 10, 49, 30, 49, 49, 0, 20,
704 0, 49, 15, 49, 5, 10, 0, 49, 49, 49,
705 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
706 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
707 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
708 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
709 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
710 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
711 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
712 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
713 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
714 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
715 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
716 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
717 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
718 49, 49, 49, 49, 49, 49
720 unsigned int hval = len;
725 hval += asso_values[static_cast<unsigned char>(str[4])];
728 hval += asso_values[static_cast<unsigned char>(str[3])];
737 KeywordHash::find (const char *str, unsigned int len)
739 static const char * const wordlist[] =
779 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
781 unsigned int key = hash (str, len);
783 if (key <= MAX_HASH_VALUE)
785 const char *s = wordlist[key];
787 if (*str == *s && !qstrcmp (str + 1, s + 1))
794 //--- end gperf generated code ----------------------------------------------------------
797 static bool nameIsActuallyPartOfType(QCString &name)
799 return KeywordHash::find(name.data(),name.length())!=0;
802 /*! Converts an argument string into an ArgumentList.
803 * \param[in] lang language of the current argument list
804 * \param[in] argsString the list of Arguments.
805 * \param[out] extraTypeChars point to string to which trailing characters
806 * for complex types are written to
809 std::unique_ptr<ArgumentList> stringToArgumentList(SrcLangExt lang, const QCString &argsString,QCString *extraTypeChars)
811 std::unique_ptr<ArgumentList> al = std::make_unique<ArgumentList>();
812 if (argsString.isEmpty()) return al;
815 defargsYY_state extra(argsString.data(),al,lang);
816 defargsYYlex_init_extra(&extra,&yyscanner);
818 defargsYYset_debug(1,yyscanner);
820 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
821 printlex(yy_flex_debug, TRUE, __FILE__, NULL);
823 defargsYYrestart( 0, yyscanner );
825 defargsYYlex(yyscanner);
826 if (yyextra->argList->empty())
828 yyextra->argList->setNoParameters(TRUE);
830 if (extraTypeChars) *extraTypeChars=yyextra->extraTypeChars;
831 //printf("stringToArgumentList(%s) result=%s\n",argsString,qPrint(argListToString(*al)));
832 printlex(yy_flex_debug, FALSE, __FILE__, NULL);
833 defargsYYlex_destroy(yyscanner);
838 #include "defargs.l.h"