7f1e1bb46aea7712b241f641585e725dfbd2f9d4
[platform/upstream/doxygen.git] / src / defargs.l
1 /******************************************************************************
2  *
3  * 
4  *
5  * Copyright (C) 1997-2015 by Dimitri van Heesch.
6  *
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.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17
18 /*! \file
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
24  *  comment blocks).
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.
28  *
29  *  Examples of input strings are:
30  *  \code
31  *    "(int a,int b) const"
32  *    "(const char *s="hello world",int=5) = 0"
33  *    "<class T,class N>"
34  *    "(char c,const char)"
35  *  \endcode
36  *
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.
41  */
42 %option never-interactive
43 %option prefix="defargsYY"
44
45 %{
46
47 /*
48  *      includes
49  */
50 #include <stdio.h>
51 //#include <iostream.h>
52 #include <assert.h>
53 #include <ctype.h>
54 #include <qregexp.h>
55
56 #include "defargs.h"
57 #include "entry.h"
58 #include "util.h"
59 #include "arguments.h"
60 #include "message.h"
61   
62 #define YY_NO_INPUT 1
63 #define YY_NO_UNISTD_H 1
64   
65 /* -----------------------------------------------------------------
66  *      state variables
67  */
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;
88
89 /* -----------------------------------------------------------------
90  */
91 #undef  YY_INPUT
92 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
93
94 static int yyread(char *buf,int max_size)
95 {
96     int c=0;
97     while( c < max_size && g_inputString[g_inputPosition] )
98     {
99         *buf = g_inputString[g_inputPosition++] ;
100         c++; buf++;
101     }
102     return c;
103 }
104
105 %}
106
107 B       [ \t]
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}\"
111
112 %option noyywrap
113
114 %x      Start
115 %x      CopyArgString
116 %x      CopyRawString
117 %x      CopyArgRound
118 %x      CopyArgRound2
119 %x      CopyArgSharp
120 %x      CopyArgCurly
121 %x      ReadFuncArgType
122 %x      ReadFuncArgDef
123 %x      ReadFuncArgPtr
124 %x      FuncQual
125 %x      ReadDocBlock
126 %x      ReadDocLine
127 %x      ReadTypeConstraint
128 %x      TrailingReturn
129
130
131 %%
132
133 <Start>[<(]                             { BEGIN(ReadFuncArgType); }
134
135 <ReadFuncArgType>{B}*                   {
136                                           g_curArgTypeName+=" ";
137                                         }
138 <ReadFuncArgType>"["[^\]]*"]"           { 
139                                           if (g_curArgTypeName.stripWhiteSpace().isEmpty())
140                                           {
141                                             g_curArgAttrib=yytext; // for M$-IDL
142                                           }
143                                           else // array type
144                                           {
145                                             g_curArgArray+=yytext;
146                                           }
147                                         }
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 );
157                                         }
158 <ReadFuncArgDef>\"                      {
159                                           g_curArgDefValue+=*yytext;
160                                           BEGIN( CopyArgString );
161                                         }
162 <ReadFuncArgType>"("([^:)]+{B}*"::")*{B}*[&*\^]+{B}*/{ID} { 
163                                           // function pointer as argument
164                                           g_curArgTypeName+=yytext;
165                                           //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
166                                           BEGIN( ReadFuncArgPtr );
167                                         }
168 <ReadFuncArgPtr>{ID}                    {
169                                           g_curArgName=yytext;
170                                         }
171 <ReadFuncArgPtr>")"{B}*"("              { // function pointer
172                                           g_curArgTypeName+=yytext;
173                                           //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
174                                           g_readArgContext = ReadFuncArgType;
175                                           g_copyArgValue=&g_curArgTypeName;
176                                           g_argRoundCount=0;
177                                           BEGIN( CopyArgRound2 );
178                                         }
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 );
184                                         }
185 <ReadFuncArgPtr>")"                     { // redundant braces detected / remove them
186                                           int i=g_curArgTypeName.findRev('('),l=g_curArgTypeName.length();
187                                           if (i!=-1)
188                                             g_curArgTypeName=g_curArgTypeName.left(i)+
189                                                            g_curArgTypeName.right(l-i-1);
190                                           g_curArgTypeName+=g_curArgName;
191                                           BEGIN( ReadFuncArgType );
192                                         }
193 <ReadFuncArgType>"<="|">="|"->"|">>"|"<<" { // handle operators in defargs
194                                           g_curArgTypeName+=yytext;
195                                         }
196 <ReadFuncArgType,ReadFuncArgDef>[({<]   {        
197                                           if (YY_START==ReadFuncArgType)
198                                           {
199                                             g_curArgTypeName+=*yytext;
200                                             g_copyArgValue=&g_curArgTypeName;
201                                           }
202                                           else // YY_START==ReadFuncArgDef
203                                           {
204                                             g_curArgDefValue+=*yytext;
205                                             g_copyArgValue=&g_curArgDefValue;
206                                           }
207                                           g_readArgContext = YY_START; 
208                                           if (*yytext=='(')
209                                           {
210                                             g_argRoundCount=0; 
211                                             BEGIN( CopyArgRound ); 
212                                           }
213                                           else if (*yytext=='{')
214                                           {
215                                             g_argCurlyCount=0; 
216                                             BEGIN( CopyArgCurly ); 
217                                           }
218                                           else // yytext=='<'
219                                           {
220                                             g_argSharpCount=0; 
221                                             g_argRoundCount=0; 
222                                             BEGIN( CopyArgSharp ); 
223                                           }
224                                         }
225 <CopyArgRound,CopyArgRound2>"("         {
226                                           g_argRoundCount++;
227                                           *g_copyArgValue += *yytext;
228                                         }
229 <CopyArgRound,CopyArgRound2>")"({B}*{ID})* {
230                                           *g_copyArgValue += yytext;
231                                           if (g_argRoundCount>0) 
232                                           {
233                                             g_argRoundCount--;
234                                           }
235                                           else 
236                                           {
237                                             if (YY_START==CopyArgRound2)
238                                             {
239                                               *g_copyArgValue+=" "+g_curArgName;
240                                             }
241                                             BEGIN( g_readArgContext );
242                                           }
243                                         }
244 <CopyArgRound>")"/{B}*                  {
245                                           *g_copyArgValue += *yytext;
246                                           if (g_argRoundCount>0) g_argRoundCount--;
247                                           else BEGIN( g_readArgContext );
248                                         }
249 <CopyArgSharp>"<<"                      {
250                                           if (g_argRoundCount>0)
251                                           {
252                                             *g_copyArgValue += yytext;
253                                           }
254                                           else
255                                           {
256                                             REJECT;
257                                           }
258                                         }
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 );
265                                           g_argRoundCount--;
266                                         }
267 <CopyArgSharp>">>"                      {
268                                           if (g_argRoundCount>0)
269                                           {
270                                             *g_copyArgValue += yytext;
271                                           }
272                                           else
273                                           {
274                                             REJECT;
275                                           }
276                                         }
277 <CopyArgSharp>"<"                       {
278                                           g_argSharpCount++;
279                                           *g_copyArgValue += *yytext;
280                                         }
281 <CopyArgSharp>">"                       {
282                                           *g_copyArgValue += *yytext;
283                                           if (g_argSharpCount>0) g_argSharpCount--;
284                                           else BEGIN( g_readArgContext );
285                                         }
286 <CopyArgSharp>"("                       {
287                                           g_argRoundCount++;
288                                           *g_copyArgValue += *yytext;
289                                         }
290 <CopyArgSharp>")"                       {
291                                           g_argRoundCount--;
292                                           *g_copyArgValue += *yytext;
293                                         }
294 <CopyArgCurly>"{"                       {
295                                           g_argCurlyCount++;
296                                           *g_copyArgValue += *yytext;
297                                         }
298 <CopyArgCurly>"}"                       {
299                                           *g_copyArgValue += *yytext;
300                                           if (g_argCurlyCount>0) g_argCurlyCount--;
301                                           else BEGIN( g_readArgContext );
302                                         }
303 <CopyArgString>\\.                      {
304                                           g_curArgDefValue+=yytext;
305                                         }
306 <CopyRawString>{RAWEND}                 {
307                                           g_curArgDefValue+=yytext;
308                                           QCString delimiter = yytext+1;
309                                           delimiter=delimiter.left(delimiter.length()-1);
310                                           if (delimiter==g_delimiter)
311                                           {
312                                             BEGIN( ReadFuncArgDef );
313                                           }
314                                         }
315 <CopyArgString>\"                       {
316                                           g_curArgDefValue+=*yytext;
317                                           BEGIN( ReadFuncArgDef );
318                                         }
319 <ReadFuncArgType>"="                    {
320                                           BEGIN( ReadFuncArgDef );
321                                         }
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 );
328                                           else
329                                             BEGIN( ReadDocBlock );
330                                         }
331 <ReadFuncArgType,ReadFuncArgDef>[,)>]   {
332                                           if (*yytext==')' && g_curArgTypeName.stripWhiteSpace().isEmpty())
333                                           {
334                                             g_curArgTypeName+=*yytext;
335                                             BEGIN(FuncQual);
336                                           }
337                                           else
338                                           {
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();
343                                             if (l>0)
344                                             {
345                                               int i=l-1;
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);
353                                               a->array.resize(0);
354                                               if (i==l-1 && g_curArgTypeName.at(i)==')') // function argument
355                                               {
356                                                 int bi=g_curArgTypeName.find('(');
357                                                 int fi=bi-1;
358                                                 //printf("func arg fi=%d\n",fi);
359                                                 while (fi>=0 && (isId(g_curArgTypeName.at(fi)) || g_curArgTypeName.at(fi)==':')) fi--;
360                                                 if (fi>=0)
361                                                 {
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);
365                                                 }
366                                                 else
367                                                 {
368                                                   a->type = g_curArgTypeName;
369                                                 }
370                                               }
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();
375
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".
379                                                 int sv=0;
380                                                 if      (a->type.left(6)=="const ")    sv=6;
381                                                 else if (a->type.left(9)=="volatile ") sv=9;
382
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"  ||
387                                                     a->type=="const"               ||
388                                                     a->type=="volatile"
389                                                    )
390                                                 { 
391                                                   a->type = a->type + " " + a->name;
392                                                   a->name.resize(0);
393                                                 }
394                                                 //printf(" --> a->type='%s' a->name='%s'\n",a->type.data(),a->name.data());
395                                               }
396                                               else // assume only the type was specified, try to determine name later 
397                                               {
398                                                 a->type = removeRedundantWhiteSpace(g_curArgTypeName);  
399                                               }
400                                               if (!a->type.isEmpty() && a->type.at(0)=='$') // typeless PHP name?
401                                               {
402                                                 a->name = a->type;
403                                                 a->type = "";
404                                               }
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])
410                                               {
411                                                 int i=a->array.find('[')-1;
412                                                 a->array = a->array.mid(1,alen-2);
413                                                 if (i>0 && a->name.isEmpty())
414                                                 {
415                                                   a->name  = a->array.left(i).stripWhiteSpace();
416                                                   a->array = a->array.mid(i);
417                                                 }
418                                               }
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);
424                                             }
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);
431                                             if (*yytext==')')
432                                             {
433                                               BEGIN(FuncQual);
434                                               //printf(">>> end of argument list\n");
435                                             }
436                                             else
437                                             {
438                                               BEGIN( ReadFuncArgType );
439                                             }
440                                           }
441                                         }
442 <ReadFuncArgType,ReadFuncArgPtr>"extends" {
443                                           g_curTypeConstraint.resize(0);
444                                           g_lastExtendsContext=YY_START;
445                                           BEGIN(ReadTypeConstraint);
446                                         }
447 <ReadFuncArgType,ReadFuncArgPtr>"$"?{ID} { 
448                                           QCString name=yytext; //resolveDefines(yytext);
449                                           if (YY_START==ReadFuncArgType && g_curArgArray=="[]") // Java style array
450                                           {
451                                             g_curArgTypeName+=" []";
452                                             g_curArgArray.resize(0);
453                                           }
454                                           //printf("resolveName `%s'->`%s'\n",yytext,name.data());
455                                           g_curArgTypeName+=name;
456                                         }
457 <ReadFuncArgType,ReadFuncArgPtr>.       { 
458                                           g_curArgTypeName+=*yytext;
459                                         }
460
461 <ReadFuncArgDef,CopyArgString>"<="|"->"|">="|">>"|"<<"  {
462                                           g_curArgDefValue+=yytext;
463                                         }
464 <ReadFuncArgDef,CopyArgString,CopyRawString>.           {
465                                           g_curArgDefValue+=*yytext;
466                                         }
467 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>{ID}  {
468                                           QCString name=yytext; //resolveDefines(yytext);
469                                           *g_copyArgValue+=name;
470                                         }
471 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>.  {
472                                           *g_copyArgValue += *yytext;
473                                         }
474 <ReadTypeConstraint>[,)>]               {
475                                           unput(*yytext);
476                                           BEGIN(g_lastExtendsContext);
477                                         }
478 <ReadTypeConstraint>.                   {
479                                           g_curTypeConstraint+=yytext;
480                                         }
481 <ReadTypeConstraint>\n                  {
482                                           g_curTypeConstraint+=' ';
483                                         }
484 <FuncQual>"const"                       {
485                                           g_argList->constSpecifier=TRUE;
486                                         }
487 <FuncQual>"volatile"                    {
488                                           g_argList->volatileSpecifier=TRUE;
489                                         }
490 <FuncQual>"&"                           {
491                                           g_argList->refQualifier=RefQualifierLValue;
492                                         }
493 <FuncQual>"&&"                          {
494                                           g_argList->refQualifier=RefQualifierRValue;
495                                         }
496 <FuncQual,TrailingReturn>"="{B}*"0"     {
497                                           g_argList->pureSpecifier=TRUE;
498                                           BEGIN(FuncQual);
499                                         }
500 <FuncQual>"->"                          { // C++11 trailing return type
501                                           g_argList->trailingReturnType=" -> ";
502                                           BEGIN(TrailingReturn);
503                                         }
504 <TrailingReturn>{B}/("final"|"override"){B}*  {
505                                           unput(*yytext);
506                                           BEGIN(FuncQual);
507                                         }
508 <TrailingReturn>.                       {
509                                           g_argList->trailingReturnType+=yytext;
510                                         }
511 <TrailingReturn>\n                      {
512                                           g_argList->trailingReturnType+=yytext;
513                                         }
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;
517                                         }
518 <ReadDocBlock>[^\*\n]+                  {
519                                           g_curArgDocs+=yytext;
520                                         }
521 <ReadDocLine>[^\n]+                     {
522                                           g_curArgDocs+=yytext;
523                                         }
524 <ReadDocBlock>"*/"                      { 
525                                           if (g_lastDocChar!=0)
526                                             unput(g_lastDocChar);
527                                           BEGIN(g_lastDocContext); 
528                                         }
529 <ReadDocLine>\n                         {
530                                           if (g_lastDocChar!=0)
531                                             unput(g_lastDocChar);
532                                           BEGIN(g_lastDocContext);
533                                         }
534 <ReadDocBlock>\n                        {
535                                           g_curArgDocs+=*yytext;
536                                         }
537 <ReadDocBlock>.                         {
538                                           g_curArgDocs+=*yytext;
539                                         }
540 <*>("/*"[*!]|"//"[/!])("<"?)            {
541                                           g_lastDocContext=YY_START;
542                                           g_lastDocChar=0;  
543                                           if (yytext[1]=='/')
544                                             BEGIN( ReadDocLine );
545                                           else
546                                             BEGIN( ReadDocBlock );
547                                         }
548 <*>\n
549 <*>.
550
551 %%
552
553 /* ----------------------------------------------------------------------------
554  */
555
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
561  */
562  
563 void stringToArgumentList(const char *argsString,ArgumentList* al,QCString *extraTypeChars)
564 {
565   if (al==0) return; 
566   if (argsString==0) return;
567   printlex(yy_flex_debug, TRUE, __FILE__, NULL);
568
569   g_copyArgValue=0;
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);
575   g_argRoundCount = 0;
576   g_argSharpCount = 0;
577   g_argCurlyCount = 0;
578   g_lastDocChar = 0;
579
580   g_inputString   = argsString;
581   g_inputPosition = 0;
582   g_curArgTypeName.resize(0);
583   g_curArgDefValue.resize(0);
584   g_curArgName.resize(0);
585   g_argList = al;
586   defargsYYrestart( defargsYYin );
587   BEGIN( Start );
588   defargsYYlex();
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);
592 }
593
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); } 
597 }
598 #endif
599