/****************************************************************************** * * * * 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" %{ /* * includes */ #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 /* ----------------------------------------------------------------- * state variables */ static const char *g_inputString; static int g_inputPosition; static ArgumentList *g_argList; static QCString *g_copyArgValue; static QCString g_curArgTypeName; static QCString g_curArgDefValue; static QCString g_curArgName; static QCString g_curArgDocs; static QCString g_curArgAttrib; static QCString g_curArgArray; static QCString g_curTypeConstraint; static QCString g_extraTypeChars; static int g_argRoundCount; static int g_argSharpCount; static int g_argCurlyCount; static int g_readArgContext; static int g_lastDocContext; static int g_lastDocChar; static int g_lastExtendsContext; static QCString g_delimiter; /* ----------------------------------------------------------------- */ #undef YY_INPUT #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); static int yyread(char *buf,int max_size) { int c=0; while( c < max_size && g_inputString[g_inputPosition] ) { *buf = g_inputString[g_inputPosition++] ; c++; buf++; } return c; } %} 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}* { g_curArgTypeName+=" "; } "["[^\]]*"]" { if (g_curArgTypeName.stripWhiteSpace().isEmpty()) { g_curArgAttrib=yytext; // for M$-IDL } else // array type { g_curArgArray+=yytext; } } "'"\\[0-7]{1,3}"'" { g_curArgDefValue+=yytext; } "'"\\."'" { g_curArgDefValue+=yytext; } "'"."'" { g_curArgDefValue+=yytext; } {RAWBEGIN} { g_curArgDefValue+=yytext; QCString text=yytext; int i=text.find('"'); g_delimiter = yytext+i+1; g_delimiter=g_delimiter.left(g_delimiter.length()-1); BEGIN( CopyRawString ); } \" { g_curArgDefValue+=*yytext; BEGIN( CopyArgString ); } "("([^:)]+{B}*"::")*{B}*[&*\^]+{B}*/{ID} { // function pointer as argument g_curArgTypeName+=yytext; //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); BEGIN( ReadFuncArgPtr ); } {ID} { g_curArgName=yytext; } ")"{B}*"(" { // function pointer g_curArgTypeName+=yytext; //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); g_readArgContext = ReadFuncArgType; g_copyArgValue=&g_curArgTypeName; g_argRoundCount=0; BEGIN( CopyArgRound2 ); } ")"/{B}*"[" { // pointer to fixed size array g_curArgTypeName+=yytext; g_curArgTypeName+=g_curArgName; //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); BEGIN( ReadFuncArgType ); } ")" { // redundant braces detected / remove them int i=g_curArgTypeName.findRev('('),l=g_curArgTypeName.length(); if (i!=-1) g_curArgTypeName=g_curArgTypeName.left(i)+ g_curArgTypeName.right(l-i-1); g_curArgTypeName+=g_curArgName; BEGIN( ReadFuncArgType ); } "<="|">="|"->"|">>"|"<<" { // handle operators in defargs g_curArgTypeName+=yytext; } [({<] { if (YY_START==ReadFuncArgType) { g_curArgTypeName+=*yytext; g_copyArgValue=&g_curArgTypeName; } else // YY_START==ReadFuncArgDef { g_curArgDefValue+=*yytext; g_copyArgValue=&g_curArgDefValue; } g_readArgContext = YY_START; if (*yytext=='(') { g_argRoundCount=0; BEGIN( CopyArgRound ); } else if (*yytext=='{') { g_argCurlyCount=0; BEGIN( CopyArgCurly ); } else // yytext=='<' { g_argSharpCount=0; g_argRoundCount=0; BEGIN( CopyArgSharp ); } } "(" { g_argRoundCount++; *g_copyArgValue += *yytext; } ")"({B}*{ID})* { *g_copyArgValue += yytext; if (g_argRoundCount>0) { g_argRoundCount--; } else { if (YY_START==CopyArgRound2) { *g_copyArgValue+=" "+g_curArgName; } BEGIN( g_readArgContext ); } } ")"/{B}* { *g_copyArgValue += *yytext; if (g_argRoundCount>0) g_argRoundCount--; else BEGIN( g_readArgContext ); } "<<" { if (g_argRoundCount>0) { *g_copyArgValue += yytext; } else { REJECT; } } ">>)" { // combined token (see bug 790320) *g_copyArgValue += yytext; if (g_argSharpCount>0) g_argSharpCount--; else BEGIN( g_readArgContext ); if (g_argSharpCount>0) g_argSharpCount--; else BEGIN( g_readArgContext ); g_argRoundCount--; } ">>" { if (g_argRoundCount>0) { *g_copyArgValue += yytext; } else { REJECT; } } "<" { g_argSharpCount++; *g_copyArgValue += *yytext; } ">" { *g_copyArgValue += *yytext; if (g_argSharpCount>0) g_argSharpCount--; else BEGIN( g_readArgContext ); } "(" { g_argRoundCount++; *g_copyArgValue += *yytext; } ")" { g_argRoundCount--; *g_copyArgValue += *yytext; } "{" { g_argCurlyCount++; *g_copyArgValue += *yytext; } "}" { *g_copyArgValue += *yytext; if (g_argCurlyCount>0) g_argCurlyCount--; else BEGIN( g_readArgContext ); } \\. { g_curArgDefValue+=yytext; } {RAWEND} { g_curArgDefValue+=yytext; QCString delimiter = yytext+1; delimiter=delimiter.left(delimiter.length()-1); if (delimiter==g_delimiter) { BEGIN( ReadFuncArgDef ); } } \" { g_curArgDefValue+=*yytext; BEGIN( ReadFuncArgDef ); } "=" { BEGIN( ReadFuncArgDef ); } [,)>]{B}*("/*"[*!]|"//"[/!])"<" { g_lastDocContext=YY_START; g_lastDocChar=*yytext; QCString text=yytext; if (text.find("//")!=-1) BEGIN( ReadDocLine ); else BEGIN( ReadDocBlock ); } [,)>] { if (*yytext==')' && g_curArgTypeName.stripWhiteSpace().isEmpty()) { g_curArgTypeName+=*yytext; BEGIN(FuncQual); } else { g_curArgTypeName=removeRedundantWhiteSpace(g_curArgTypeName); g_curArgDefValue=g_curArgDefValue.stripWhiteSpace(); //printf("curArgType=`%s' curArgDefVal=`%s'\n",g_curArgTypeName.data(),g_curArgDefValue.data()); int l=g_curArgTypeName.length(); if (l>0) { int i=l-1; while (i>=0 && (isspace((uchar)g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='.')) i--; while (i>=0 && (isId(g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='$')) i--; Argument *a = new Argument; a->attrib = g_curArgAttrib.copy(); a->typeConstraint = g_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 && g_curArgTypeName.at(i)==')') // function argument { int bi=g_curArgTypeName.find('('); int fi=bi-1; //printf("func arg fi=%d\n",fi); while (fi>=0 && (isId(g_curArgTypeName.at(fi)) || g_curArgTypeName.at(fi)==':')) fi--; if (fi>=0) { a->type = g_curArgTypeName.left(fi+1); a->name = g_curArgTypeName.mid(fi+1,bi-fi-1).stripWhiteSpace(); a->array = g_curArgTypeName.right(l-bi); } else { a->type = g_curArgTypeName; } } else if (i>=0 && g_curArgTypeName.at(i)!=':') { // type contains a name a->type = removeRedundantWhiteSpace(g_curArgTypeName.left(i+1)).stripWhiteSpace(); a->name = g_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" || a->type=="const" || a->type=="volatile" ) { 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(g_curArgTypeName); } if (!a->type.isEmpty() && a->type.at(0)=='$') // typeless PHP name? { a->name = a->type; a->type = ""; } a->array += removeRedundantWhiteSpace(g_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]) { int 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 = g_curArgDefValue.copy(); //printf("a->type=%s a->name=%s a->defval=\"%s\"\n",a->type.data(),a->name.data(),a->defval.data()); a->docs = g_curArgDocs.stripWhiteSpace(); //printf("Argument `%s' `%s' adding docs=`%s'\n",a->type.data(),a->name.data(),a->docs.data()); g_argList->append(a); } g_curArgAttrib.resize(0); g_curArgTypeName.resize(0); g_curArgDefValue.resize(0); g_curArgArray.resize(0); g_curArgDocs.resize(0); g_curTypeConstraint.resize(0); if (*yytext==')') { BEGIN(FuncQual); //printf(">>> end of argument list\n"); } else { BEGIN( ReadFuncArgType ); } } } "extends" { g_curTypeConstraint.resize(0); g_lastExtendsContext=YY_START; BEGIN(ReadTypeConstraint); } "$"?{ID} { QCString name=yytext; //resolveDefines(yytext); if (YY_START==ReadFuncArgType && g_curArgArray=="[]") // Java style array { g_curArgTypeName+=" []"; g_curArgArray.resize(0); } //printf("resolveName `%s'->`%s'\n",yytext,name.data()); g_curArgTypeName+=name; } . { g_curArgTypeName+=*yytext; } "<="|"->"|">="|">>"|"<<" { g_curArgDefValue+=yytext; } . { g_curArgDefValue+=*yytext; } {ID} { QCString name=yytext; //resolveDefines(yytext); *g_copyArgValue+=name; } . { *g_copyArgValue += *yytext; } [,)>] { unput(*yytext); BEGIN(g_lastExtendsContext); } . { g_curTypeConstraint+=yytext; } \n { g_curTypeConstraint+=' '; } "const" { g_argList->constSpecifier=TRUE; } "volatile" { g_argList->volatileSpecifier=TRUE; } "&" { g_argList->refQualifier=RefQualifierLValue; } "&&" { g_argList->refQualifier=RefQualifierRValue; } "="{B}*"0" { g_argList->pureSpecifier=TRUE; BEGIN(FuncQual); } "->" { // C++11 trailing return type g_argList->trailingReturnType=" -> "; BEGIN(TrailingReturn); } {B}/("final"|"override"){B}* { unput(*yytext); BEGIN(FuncQual); } . { g_argList->trailingReturnType+=yytext; } \n { g_argList->trailingReturnType+=yytext; } ")"{B}*"["[^]]*"]" { // for functions returning a pointer to an array, // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]" g_extraTypeChars=yytext; } [^\*\n]+ { g_curArgDocs+=yytext; } [^\n]+ { g_curArgDocs+=yytext; } "*/" { if (g_lastDocChar!=0) unput(g_lastDocChar); BEGIN(g_lastDocContext); } \n { if (g_lastDocChar!=0) unput(g_lastDocChar); BEGIN(g_lastDocContext); } \n { g_curArgDocs+=*yytext; } . { g_curArgDocs+=*yytext; } <*>("/*"[*!]|"//"[/!])("<"?) { g_lastDocContext=YY_START; g_lastDocChar=0; if (yytext[1]=='/') BEGIN( ReadDocLine ); else BEGIN( ReadDocBlock ); } <*>\n <*>. %% /* ---------------------------------------------------------------------------- */ /*! 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 */ void stringToArgumentList(const char *argsString,ArgumentList* al,QCString *extraTypeChars) { if (al==0) return; if (argsString==0) return; printlex(yy_flex_debug, TRUE, __FILE__, NULL); g_copyArgValue=0; g_curArgDocs.resize(0); g_curArgAttrib.resize(0); g_curArgArray.resize(0); g_curTypeConstraint.resize(0); g_extraTypeChars.resize(0); g_argRoundCount = 0; g_argSharpCount = 0; g_argCurlyCount = 0; g_lastDocChar = 0; g_inputString = argsString; g_inputPosition = 0; g_curArgTypeName.resize(0); g_curArgDefValue.resize(0); g_curArgName.resize(0); g_argList = al; defargsYYrestart( defargsYYin ); BEGIN( Start ); defargsYYlex(); if (extraTypeChars) *extraTypeChars=g_extraTypeChars; //printf("stringToArgumentList(%s) result=%s\n",argsString,argListToString(al).data()); printlex(yy_flex_debug, FALSE, __FILE__, NULL); } #if !defined(YY_FLEX_SUBMINOR_VERSION) extern "C" { // some bogus code to keep the compiler happy void defargsYYdummy() { yy_flex_realloc(0,0); } } #endif