/****************************************************************************** * * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * Documents produced by Doxygen are derivative works derived from the * input used in their production; they are not affected by this license. * */ /*! \file * This scanner is used to convert a string into a list of function or * template arguments. Each parsed argument results in a Argument struct, * that is put into an ArgumentList in declaration order. * Comment blocks for arguments can also be included in the string. * The argument string does not contain new-lines (except inside any * comment blocks). * An Argument consists of the string fields: * type,name,default value, and documentation * The Argument list as a whole can be pure, constant or volatile. * * Examples of input strings are: * \code * "(int a,int b) const" * "(const char *s="hello world",int=5) = 0" * "" * "(char c,const char)" * \endcode * * Note: It is not always possible to distinguish between the name and * type of an argument. In case of doubt the name is added to the * type, and the matchArgumentList in util.cpp is be used to * further determine the correct separation. */ %option never-interactive %option prefix="defargsYY" %option reentrant %option extra-type="struct defargsYY_state *" %top{ #include } %{ /* * includes */ #include //#include #include #include #include #include #include "defargs.h" #include "entry.h" #include "util.h" #include "arguments.h" #include "message.h" #define YY_NO_INPUT 1 #define YY_NO_UNISTD_H 1 #define USE_STATE2STRING 0 /* ----------------------------------------------------------------- * state variables */ struct defargsYY_state { defargsYY_state(const char *inStr,std::unique_ptr &al,SrcLangExt l) : inputString(inStr), argList(al), lang(l) {} const char *inputString; std::unique_ptr &argList; SrcLangExt lang; int inputPosition = 0; QCString *copyArgValue = 0; QCString curArgTypeName; QCString curArgDefValue; QCString curArgName; QCString curArgDocs; QCString curArgAttrib; QCString curArgArray; QCString curTypeConstraint; QCString extraTypeChars; int argRoundCount = 0; int argSharpCount = 0; int argCurlyCount = 0; int readArgContext = 0; int lastDocContext = 0; int lastDocChar = 0; int lastExtendsContext = 0; QCString delimiter; }; #if USE_STATE2STRING static const char *stateToString(int state); #endif static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size); static bool nameIsActuallyPartOfType(QCString &name); /* ----------------------------------------------------------------- */ #undef YY_INPUT #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size); %} B [ \t] ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"(" RAWEND ")"[^ \t\(\)\\]{0,16}\" %option noyywrap %x Start %x CopyArgString %x CopyRawString %x CopyArgRound %x CopyArgRound2 %x CopyArgSharp %x CopyArgCurly %x ReadFuncArgType %x ReadFuncArgDef %x ReadFuncArgPtr %x FuncQual %x ReadDocBlock %x ReadDocLine %x ReadTypeConstraint %x TrailingReturn %% [<(] { BEGIN(ReadFuncArgType); } {B}* { yyextra->curArgTypeName+=" "; } "["[^\]]*"]" { if (yyextra->curArgTypeName.stripWhiteSpace().isEmpty()) { yyextra->curArgAttrib=yytext; // for M$-IDL } else // array type { yyextra->curArgArray+=yytext; } } "'"\\[0-7]{1,3}"'" { yyextra->curArgDefValue+=yytext; } "'"\\."'" { yyextra->curArgDefValue+=yytext; } "'"."'" { yyextra->curArgDefValue+=yytext; } {RAWBEGIN} { yyextra->curArgDefValue+=yytext; QCString text=yytext; int i=text.find('"'); yyextra->delimiter = yytext+i+1; yyextra->delimiter=yyextra->delimiter.left(yyextra->delimiter.length()-1); BEGIN( CopyRawString ); } \" { yyextra->curArgDefValue+=*yytext; BEGIN( CopyArgString ); } "("([^:)]+{B}*"::")*{B}*[&*\^]+{B}*/{ID} { // function pointer as argument yyextra->curArgTypeName+=yytext; //yyextra->curArgTypeName=yyextra->curArgTypeName.simplifyWhiteSpace(); BEGIN( ReadFuncArgPtr ); } {ID} { yyextra->curArgName=yytext; } ")"{B}*"(" { // function pointer yyextra->curArgTypeName+=yytext; //yyextra->curArgTypeName=yyextra->curArgTypeName.simplifyWhiteSpace(); yyextra->readArgContext = ReadFuncArgType; yyextra->copyArgValue=&yyextra->curArgTypeName; yyextra->argRoundCount=0; BEGIN( CopyArgRound2 ); } ")"/{B}*"[" { // pointer to fixed size array yyextra->curArgTypeName+=yytext; yyextra->curArgTypeName+=yyextra->curArgName; //yyextra->curArgTypeName=yyextra->curArgTypeName.simplifyWhiteSpace(); BEGIN( ReadFuncArgType ); } ")" { // redundant braces detected / remove them int i=yyextra->curArgTypeName.findRev('('),l=yyextra->curArgTypeName.length(); if (i!=-1) yyextra->curArgTypeName=yyextra->curArgTypeName.left(i)+ yyextra->curArgTypeName.right(l-i-1); yyextra->curArgTypeName+=yyextra->curArgName; BEGIN( ReadFuncArgType ); } "<="|">="|"->"|">>"|"<<" { // handle operators in defargs yyextra->curArgTypeName+=yytext; } [({<] { if (YY_START==ReadFuncArgType) { yyextra->curArgTypeName+=*yytext; yyextra->copyArgValue=&yyextra->curArgTypeName; } else // YY_START==ReadFuncArgDef { yyextra->curArgDefValue+=*yytext; yyextra->copyArgValue=&yyextra->curArgDefValue; } yyextra->readArgContext = YY_START; if (*yytext=='(') { yyextra->argRoundCount=0; BEGIN( CopyArgRound ); } else if (*yytext=='{') { yyextra->argCurlyCount=0; BEGIN( CopyArgCurly ); } else // yytext=='<' { yyextra->argSharpCount=0; yyextra->argRoundCount=0; BEGIN( CopyArgSharp ); } } "(" { yyextra->argRoundCount++; *yyextra->copyArgValue += *yytext; } ")"({B}*{ID})* { *yyextra->copyArgValue += yytext; if (yyextra->argRoundCount>0) { yyextra->argRoundCount--; } else { if (YY_START==CopyArgRound2) { *yyextra->copyArgValue+=" "+yyextra->curArgName; } BEGIN( yyextra->readArgContext ); } } ")"/{B}* { *yyextra->copyArgValue += *yytext; if (yyextra->argRoundCount>0) yyextra->argRoundCount--; else BEGIN( yyextra->readArgContext ); } "<<" { if (yyextra->argRoundCount>0) { // for e.g. < typename A = (i<<3) > *yyextra->copyArgValue += yytext; } else { REJECT; } } ">>" { if (yyextra->argRoundCount>0) { // for e.g. < typename A = (i>>3) > *yyextra->copyArgValue += yytext; } else { REJECT; } } "<" { // don't count < inside (, e.g. for things like: < typename A=(i<6) > if (yyextra->argRoundCount==0) yyextra->argSharpCount++; *yyextra->copyArgValue += *yytext; } ">" { *yyextra->copyArgValue += *yytext; if (yyextra->argRoundCount>0 && yyextra->argSharpCount==0) { // don't count > inside ) } else { if (yyextra->argSharpCount>0) { yyextra->argSharpCount--; } else { BEGIN( yyextra->readArgContext ); } } } "(" { yyextra->argRoundCount++; *yyextra->copyArgValue += *yytext; } ")" { yyextra->argRoundCount--; *yyextra->copyArgValue += *yytext; } "{" { yyextra->argCurlyCount++; *yyextra->copyArgValue += *yytext; } "}" { *yyextra->copyArgValue += *yytext; if (yyextra->argCurlyCount>0) yyextra->argCurlyCount--; else BEGIN( yyextra->readArgContext ); } \\. { yyextra->curArgDefValue+=yytext; } {RAWEND} { yyextra->curArgDefValue+=yytext; QCString delimiter = yytext+1; delimiter=delimiter.left(delimiter.length()-1); if (delimiter==yyextra->delimiter) { BEGIN( ReadFuncArgDef ); } } \" { yyextra->curArgDefValue+=*yytext; BEGIN( ReadFuncArgDef ); } "=" { BEGIN( ReadFuncArgDef ); } [,)>]{B}*("/*"[*!]|"//"[/!])"<" { yyextra->lastDocContext=YY_START; yyextra->lastDocChar=*yytext; QCString text=yytext; if (text.find("//")!=-1) BEGIN( ReadDocLine ); else BEGIN( ReadDocBlock ); } [,)>] { if (*yytext==')' && yyextra->curArgTypeName.stripWhiteSpace().isEmpty()) { yyextra->curArgTypeName+=*yytext; BEGIN(FuncQual); } else { yyextra->curArgTypeName=removeRedundantWhiteSpace(yyextra->curArgTypeName); yyextra->curArgDefValue=yyextra->curArgDefValue.stripWhiteSpace(); //printf("curArgType='%s' curArgDefVal='%s'\n",yyextra->curArgTypeName.data(),yyextra->curArgDefValue.data()); int l=yyextra->curArgTypeName.length(); if (l>0) { int i=l-1; while (i>=0 && (isspace((uchar)yyextra->curArgTypeName.at(i)) || yyextra->curArgTypeName.at(i)=='.')) i--; while (i>=0 && (isId(yyextra->curArgTypeName.at(i)) || yyextra->curArgTypeName.at(i)=='$')) i--; Argument a; a.attrib = yyextra->curArgAttrib.copy(); a.typeConstraint = yyextra->curTypeConstraint.stripWhiteSpace(); //printf("a->type=%s a->name=%s i=%d l=%d\n", // a->type.data(),a->name.data(),i,l); a.array.resize(0); if (i==l-1 && yyextra->curArgTypeName.at(i)==')') // function argument { int bi=yyextra->curArgTypeName.find('('); int fi=bi-1; //printf("func arg fi=%d\n",fi); while (fi>=0 && (isId(yyextra->curArgTypeName.at(fi)) || yyextra->curArgTypeName.at(fi)==':')) fi--; if (fi>=0) { a.type = yyextra->curArgTypeName.left(fi+1); a.name = yyextra->curArgTypeName.mid(fi+1,bi-fi-1).stripWhiteSpace(); a.array = yyextra->curArgTypeName.right(l-bi); } else { a.type = yyextra->curArgTypeName; } } else if (i>=0 && yyextra->curArgTypeName.at(i)!=':') { // type contains a name a.type = removeRedundantWhiteSpace(yyextra->curArgTypeName.left(i+1)).stripWhiteSpace(); a.name = yyextra->curArgTypeName.right(l-i-1).stripWhiteSpace(); // if the type becomes a type specifier only then we make a mistake // and need to correct it to avoid seeing a nameless parameter // "struct A" as a parameter with type "struct" and name "A". int sv=0; if (a.type.left(6)=="const ") sv=6; else if (a.type.left(9)=="volatile ") sv=9; if (a.type.mid(sv)=="struct" || a.type.mid(sv)=="union" || a.type.mid(sv)=="class" || a.type.mid(sv)=="typename" || nameIsActuallyPartOfType(a.name) ) { a.type = a.type + " " + a.name; a.name.resize(0); } //printf(" --> a->type='%s' a->name='%s'\n",a->type.data(),a->name.data()); } else // assume only the type was specified, try to determine name later { a.type = removeRedundantWhiteSpace(yyextra->curArgTypeName); } if (!a.type.isEmpty() && a.type.at(0)=='$') // typeless PHP name? { a.name = a.type; a.type = ""; } a.array += removeRedundantWhiteSpace(yyextra->curArgArray); //printf("array=%s\n",a->array.data()); int alen = a.array.length(); if (alen>2 && a.array.at(0)=='(' && a.array.at(alen-1)==')') // fix-up for int *(a[10]) { i=a.array.find('[')-1; a.array = a.array.mid(1,alen-2); if (i>0 && a.name.isEmpty()) { a.name = a.array.left(i).stripWhiteSpace(); a.array = a.array.mid(i); } } a.defval = yyextra->curArgDefValue.copy(); //printf("a->type=%s a->name=%s a->defval=\"%s\"\n",a->type.data(),a->name.data(),a->defval.data()); a.docs = yyextra->curArgDocs.stripWhiteSpace(); //printf("Argument '%s' '%s' adding docs='%s'\n",a->type.data(),a->name.data(),a->docs.data()); yyextra->argList->push_back(a); } yyextra->curArgAttrib.resize(0); yyextra->curArgTypeName.resize(0); yyextra->curArgDefValue.resize(0); yyextra->curArgArray.resize(0); yyextra->curArgDocs.resize(0); yyextra->curTypeConstraint.resize(0); if (*yytext==')') { BEGIN(FuncQual); //printf(">>> end of argument list\n"); } else { BEGIN( ReadFuncArgType ); } } } "extends" { if (yyextra->lang!=SrcLangExt_Java) { REJECT; } else { yyextra->curTypeConstraint.resize(0); yyextra->lastExtendsContext=YY_START; BEGIN(ReadTypeConstraint); } } "$"?{ID} { QCString name=yytext; //resolveDefines(yytext); if (YY_START==ReadFuncArgType && yyextra->curArgArray=="[]") // Java style array { yyextra->curArgTypeName+=" []"; yyextra->curArgArray.resize(0); } //printf("resolveName '%s'->'%s'\n",yytext,name.data()); yyextra->curArgTypeName+=name; } . { yyextra->curArgTypeName+=*yytext; } "<="|"->"|">="|">>"|"<<" { yyextra->curArgDefValue+=yytext; } . { yyextra->curArgDefValue+=*yytext; } {ID} { QCString name=yytext; //resolveDefines(yytext); *yyextra->copyArgValue+=name; } . { *yyextra->copyArgValue += *yytext; } [,)>] { unput(*yytext); BEGIN(yyextra->lastExtendsContext); } . { yyextra->curTypeConstraint+=yytext; } \n { yyextra->curTypeConstraint+=' '; } "const" { yyextra->argList->constSpecifier=TRUE; } "volatile" { yyextra->argList->volatileSpecifier=TRUE; } "&" { yyextra->argList->refQualifier=RefQualifierLValue; } "&&" { yyextra->argList->refQualifier=RefQualifierRValue; } "="{B}*"0" { yyextra->argList->pureSpecifier=TRUE; BEGIN(FuncQual); } "->" { // C++11 trailing return type yyextra->argList->trailingReturnType=" -> "; BEGIN(TrailingReturn); } {B}/("final"|"override"){B}* { unput(*yytext); BEGIN(FuncQual); } . { yyextra->argList->trailingReturnType+=yytext; } \n { yyextra->argList->trailingReturnType+=yytext; } ")"{B}*"["[^]]*"]" { // for functions returning a pointer to an array, // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]" yyextra->extraTypeChars=yytext; } [^\*\n]+ { yyextra->curArgDocs+=yytext; } [^\n]+ { yyextra->curArgDocs+=yytext; } "*/" { if (yyextra->lastDocChar!=0) unput(yyextra->lastDocChar); BEGIN(yyextra->lastDocContext); } \n { if (yyextra->lastDocChar!=0) unput(yyextra->lastDocChar); BEGIN(yyextra->lastDocContext); } \n { yyextra->curArgDocs+=*yytext; } . { yyextra->curArgDocs+=*yytext; } <*>("/*"[*!]|"//"[/!])("<"?) { yyextra->lastDocContext=YY_START; yyextra->lastDocChar=0; if (yytext[1]=='/') BEGIN( ReadDocLine ); else BEGIN( ReadDocBlock ); } <*>\n <*>. %% /* ---------------------------------------------------------------------------- */ static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; yy_size_t c=0; while( c < max_size && yyextra->inputString[yyextra->inputPosition] ) { *buf = yyextra->inputString[yyextra->inputPosition++] ; c++; buf++; } return c; } /* The following code is generated using 'gperf keywords.txt' where keywords.txt has the following content --------------------------------- %define class-name KeywordHash %define lookup-function-name find %readonly-tables %language=C++ %% unsigned signed bool char char8_t char16_t char32_t wchar_t int short long float double int8_t int16_t int32_t int64_t intmax_t intptr_t uint8_t uint16_t uint32_t uint64_t uintmax_t uintptr_t const volatile void %% --------------------------------- */ //--- begin gperf generated code ---------------------------------------------------------- #define TOTAL_KEYWORDS 28 #define MIN_WORD_LENGTH 3 #define MAX_WORD_LENGTH 9 #define MIN_HASH_VALUE 3 #define MAX_HASH_VALUE 48 /* maximum key range = 46, duplicates = 0 */ class KeywordHash { private: static inline unsigned int hash (const char *str, unsigned int len); public: static const char *find (const char *str, unsigned int len); }; inline unsigned int KeywordHash::hash (const char *str, unsigned int len) { static const unsigned char asso_values[] = { 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 5, 5, 30, 0, 49, 25, 49, 10, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, 49, 0, 5, 49, 15, 0, 49, 10, 49, 30, 49, 49, 0, 20, 0, 49, 15, 49, 5, 10, 0, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49 }; unsigned int hval = len; switch (hval) { default: hval += asso_values[static_cast(str[4])]; /*FALLTHROUGH*/ case 4: hval += asso_values[static_cast(str[3])]; /*FALLTHROUGH*/ case 3: break; } return hval; } const char * KeywordHash::find (const char *str, unsigned int len) { static const char * const wordlist[] = { "", "", "", "int", "bool", "float", "signed", "", "volatile", "char", "short", "double", "wchar_t", "uint16_t", "long", "const", "int8_t", "uint8_t", "char16_t", "void", "", "", "char8_t", "intptr_t", "uintptr_t", "", "", "", "intmax_t", "uintmax_t", "", "", "int64_t", "uint64_t", "", "", "", "int16_t", "uint32_t", "", "", "", "int32_t", "char32_t", "", "", "", "", "unsigned" }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { unsigned int key = hash (str, len); if (key <= MAX_HASH_VALUE) { const char *s = wordlist[key]; if (*str == *s && !qstrcmp (str + 1, s + 1)) return s; } } return 0; } //--- end gperf generated code ---------------------------------------------------------- /* bug_520975 */ static bool nameIsActuallyPartOfType(QCString &name) { return KeywordHash::find(name.data(),name.length())!=0; } /*! Converts an argument string into an ArgumentList. * \param[in] argsString the list of Arguments. * \param[out] al a reference to resulting argument list pointer. * \param[out] extraTypeChars point to string to which trailing characters * for complex types are written to */ std::unique_ptr stringToArgumentList(SrcLangExt lang, const char *argsString,QCString *extraTypeChars) { std::unique_ptr al = std::make_unique(); if (argsString==0) return al; yyscan_t yyscanner; defargsYY_state extra(argsString,al,lang); defargsYYlex_init_extra(&extra,&yyscanner); #ifdef FLEX_DEBUG defargsYYset_debug(1,yyscanner); #endif struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; printlex(yy_flex_debug, TRUE, __FILE__, NULL); defargsYYrestart( 0, yyscanner ); BEGIN( Start ); defargsYYlex(yyscanner); if (yyextra->argList->empty()) { yyextra->argList->noParameters = TRUE; } if (extraTypeChars) *extraTypeChars=yyextra->extraTypeChars; //printf("stringToArgumentList(%s) result=%s\n",argsString,argListToString(al).data()); printlex(yy_flex_debug, FALSE, __FILE__, NULL); defargsYYlex_destroy(yyscanner); return al; } #if USE_STATE2STRING #include "defargs.l.h" #endif