Fix for UBSan build
[platform/upstream/doxygen.git] / src / defargs.l
1 /******************************************************************************
2  *
3  * 
4  *
5  * Copyright (C) 1997-2012 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
43 %{
44
45 /*
46  *      includes
47  */
48 #include "qtbc.h"
49 #include <stdio.h>
50 //#include <iostream.h>
51 #include <assert.h>
52 #include <ctype.h>
53 #include <qregexp.h>
54
55 #include "defargs.h"
56 #include "entry.h"
57 #include "util.h"
58 #include "arguments.h"
59   
60 #define YY_NEVER_INTERACTIVE 1
61 #define YY_NO_INPUT 1
62   
63 /* -----------------------------------------------------------------
64  *      state variables
65  */
66 static const char      *g_inputString;
67 static int              g_inputPosition;
68 static ArgumentList    *g_argList;
69 static QCString        *g_copyArgValue;
70 static QCString         g_curArgTypeName;
71 static QCString         g_curArgDefValue;
72 static QCString         g_curArgName;
73 static QCString         g_curArgDocs;
74 static QCString         g_curArgAttrib;
75 static QCString         g_curArgArray;
76 static QCString         g_extraTypeChars;
77 static int              g_argRoundCount;
78 static int              g_argSharpCount;
79 static int              g_argCurlyCount;
80 static int              g_readArgContext;
81 static int              g_lastDocContext;
82 static int              g_lastDocChar;
83 static QCString         g_delimiter;
84
85 /* -----------------------------------------------------------------
86  */
87 #undef  YY_INPUT
88 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
89
90 static int yyread(char *buf,int max_size)
91 {
92     int c=0;
93     while( c < max_size && g_inputString[g_inputPosition] )
94     {
95         *buf = g_inputString[g_inputPosition++] ;
96         c++; buf++;
97     }
98     return c;
99 }
100
101 %}
102
103 B       [ \t]
104 ID      [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
105 RAWBEGIN  (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
106 RAWEND    ")"[^ \t\(\)\\]{0,16}\"
107
108 %option noyywrap
109
110 %x      Start
111 %x      CopyArgString
112 %x      CopyRawString
113 %x      CopyArgRound
114 %x      CopyArgRound2
115 %x      CopyArgSharp
116 %x      CopyArgCurly
117 %x      ReadFuncArgType
118 %x      ReadFuncArgDef
119 %x      ReadFuncArgPtr
120 %x      FuncQual
121 %x      ReadDocBlock
122 %x      ReadDocLine
123 %x      TrailingReturn
124
125
126 %%
127
128 <Start>[<(]                             { BEGIN(ReadFuncArgType); }
129
130 <ReadFuncArgType>{B}*                   {
131                                           g_curArgTypeName+=" ";
132                                         }
133 <ReadFuncArgType>"["[^\]]*"]"           { 
134                                           if (g_curArgTypeName.stripWhiteSpace().isEmpty())
135                                           {
136                                             g_curArgAttrib=yytext; // for M$-IDL
137                                           }
138                                           else // array type
139                                           {
140                                             g_curArgArray+=yytext;
141                                           }
142                                         }
143 <ReadFuncArgDef>"'"\\[0-7]{1,3}"'"      { g_curArgDefValue+=yytext; }
144 <ReadFuncArgDef>"'"\\."'"               { g_curArgDefValue+=yytext; }
145 <ReadFuncArgDef>"'"."'"                 { g_curArgDefValue+=yytext; }
146 <ReadFuncArgDef>{RAWBEGIN}              { g_curArgDefValue+=yytext; 
147                                           QCString text=yytext;
148                                           int i=text.find('"');
149                                           g_delimiter = yytext+i+1;
150                                           g_delimiter=g_delimiter.left(g_delimiter.length()-1);
151                                           BEGIN( CopyRawString );
152                                         }
153 <ReadFuncArgDef>\"                      {
154                                           g_curArgDefValue+=*yytext;
155                                           BEGIN( CopyArgString );
156                                         }
157 <ReadFuncArgType>"("([^:)]+{B}*"::")*{B}*[&*\^]+{B}*/{ID} { 
158                                           // function pointer as argument
159                                           g_curArgTypeName+=yytext;
160                                           //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
161                                           BEGIN( ReadFuncArgPtr );
162                                         }
163 <ReadFuncArgPtr>{ID}                    {
164                                           g_curArgName=yytext;
165                                         }
166 <ReadFuncArgPtr>")"{B}*"("              { // function pointer
167                                           g_curArgTypeName+=yytext;
168                                           //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
169                                           g_readArgContext = ReadFuncArgType;
170                                           g_copyArgValue=&g_curArgTypeName;
171                                           g_argRoundCount=0;
172                                           BEGIN( CopyArgRound2 );
173                                         }
174 <ReadFuncArgPtr>")"/{B}*"["             { // pointer to fixed size array
175                                           g_curArgTypeName+=yytext;
176                                           g_curArgTypeName+=g_curArgName;
177                                           //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace();
178                                           BEGIN( ReadFuncArgType );
179                                         }
180 <ReadFuncArgPtr>")"                     { // redundant braces detected / remove them
181                                           int i=g_curArgTypeName.findRev('('),l=g_curArgTypeName.length();
182                                           if (i!=-1)
183                                             g_curArgTypeName=g_curArgTypeName.left(i)+
184                                                            g_curArgTypeName.right(l-i-1);
185                                           g_curArgTypeName+=g_curArgName;
186                                           BEGIN( ReadFuncArgType );
187                                         }
188 <ReadFuncArgType>"<="|">="|"->"|">>"|"<<" { // handle operators in defargs
189                                           g_curArgTypeName+=yytext;
190                                         }
191 <ReadFuncArgType,ReadFuncArgDef>[({<]   {        
192                                           if (YY_START==ReadFuncArgType)
193                                           {
194                                             g_curArgTypeName+=*yytext;
195                                             g_copyArgValue=&g_curArgTypeName;
196                                           }
197                                           else // YY_START==ReadFuncArgDef
198                                           {
199                                             g_curArgDefValue+=*yytext;
200                                             g_copyArgValue=&g_curArgDefValue;
201                                           }
202                                           g_readArgContext = YY_START; 
203                                           if (*yytext=='(')
204                                           {
205                                             g_argRoundCount=0; 
206                                             BEGIN( CopyArgRound ); 
207                                           }
208                                           else if (*yytext=='{')
209                                           {
210                                             g_argCurlyCount=0; 
211                                             BEGIN( CopyArgCurly ); 
212                                           }
213                                           else // yytext=='<'
214                                           {
215                                             g_argSharpCount=0; 
216                                             BEGIN( CopyArgSharp ); 
217                                           }
218                                         }
219 <CopyArgRound,CopyArgRound2>"("         {
220                                           g_argRoundCount++;
221                                           *g_copyArgValue += *yytext;
222                                         }
223 <CopyArgRound,CopyArgRound2>")"({B}*{ID})* {
224                                           *g_copyArgValue += yytext;
225                                           if (g_argRoundCount>0) 
226                                           {
227                                             g_argRoundCount--;
228                                           }
229                                           else 
230                                           {
231                                             if (YY_START==CopyArgRound2)
232                                             {
233                                               *g_copyArgValue+=" "+g_curArgName;
234                                             }
235                                             BEGIN( g_readArgContext );
236                                           }
237                                         }
238 <CopyArgRound>")"/{B}*                  {
239                                           *g_copyArgValue += *yytext;
240                                           if (g_argRoundCount>0) g_argRoundCount--;
241                                           else BEGIN( g_readArgContext );
242                                         }
243 <CopyArgSharp>"<"                       {
244                                           g_argSharpCount++;
245                                           *g_copyArgValue += *yytext;
246                                         }
247 <CopyArgSharp>">"                       {
248                                           *g_copyArgValue += *yytext;
249                                           if (g_argSharpCount>0) g_argSharpCount--;
250                                           else BEGIN( g_readArgContext );
251                                         }
252 <CopyArgCurly>"{"                       {
253                                           g_argCurlyCount++;
254                                           *g_copyArgValue += *yytext;
255                                         }
256 <CopyArgCurly>"}"                       {
257                                           *g_copyArgValue += *yytext;
258                                           if (g_argCurlyCount>0) g_argCurlyCount--;
259                                           else BEGIN( g_readArgContext );
260                                         }
261 <CopyArgString>\\.                      {
262                                           g_curArgDefValue+=yytext;
263                                         }
264 <CopyRawString>{RAWEND}                 {
265                                           g_curArgDefValue+=yytext;
266                                           QCString delimiter = yytext+1;
267                                           delimiter=delimiter.left(delimiter.length()-1);
268                                           if (delimiter==g_delimiter)
269                                           {
270                                             BEGIN( ReadFuncArgDef );
271                                           }
272                                         }
273 <CopyArgString>\"                       {
274                                           g_curArgDefValue+=*yytext;
275                                           BEGIN( ReadFuncArgDef );
276                                         }
277 <ReadFuncArgType>"="                    {
278                                           BEGIN( ReadFuncArgDef );
279                                         }
280 <ReadFuncArgType,ReadFuncArgDef>[,)>]{B}*("/*"[*!]|"//"[/!])"<" {
281                                           g_lastDocContext=YY_START;
282                                           g_lastDocChar=*yytext;  
283                                           QCString text=yytext;
284                                           if (text.find("//")!=-1)
285                                             BEGIN( ReadDocLine );
286                                           else
287                                             BEGIN( ReadDocBlock );
288                                         }
289 <ReadFuncArgType,ReadFuncArgDef>[,)>]   {
290                                           if (*yytext==')' && g_curArgTypeName.stripWhiteSpace().isEmpty())
291                                           {
292                                             g_curArgTypeName+=*yytext;
293                                             BEGIN(FuncQual);
294                                           }
295                                           else
296                                           {
297                                             g_curArgTypeName=removeRedundantWhiteSpace(g_curArgTypeName);
298                                             g_curArgDefValue=g_curArgDefValue.stripWhiteSpace();
299                                             //printf("curArgType=`%s' curArgDefVal=`%s'\n",g_curArgTypeName.data(),g_curArgDefValue.data());
300                                             int l=g_curArgTypeName.length();
301                                             if (l>0)
302                                             {
303                                               int i=l-1;
304                                               while (i>=0 && (isspace((uchar)g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='.')) i--;
305                                               while (i>=0 && (isId(g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='$')) i--;
306                                               Argument *a = new Argument; 
307                                               a->attrib = g_curArgAttrib.copy();
308                                               //printf("a->type=%s a->name=%s i=%d l=%d\n",
309                                               //        a->type.data(),a->name.data(),i,l);
310                                               a->array.resize(0);
311                                               if (i==l-1 && g_curArgTypeName.at(i)==')') // function argument
312                                               {
313                                                 int bi=g_curArgTypeName.find('(');
314                                                 int fi=bi-1;
315                                                 //printf("func arg fi=%d\n",fi);
316                                                 while (fi>=0 && isId(g_curArgTypeName.at(fi))) fi--;
317                                                 if (fi>=0)
318                                                 {
319                                                   a->type  = g_curArgTypeName.left(fi+1);
320                                                   a->name  = g_curArgTypeName.mid(fi+1,bi-fi-1).stripWhiteSpace();
321                                                   a->array = g_curArgTypeName.right(l-bi);
322                                                 }
323                                                 else
324                                                 {
325                                                   a->type = g_curArgTypeName;
326                                                 }
327                                               }
328                                               else if (i>=0 && g_curArgTypeName.at(i)!=':')
329                                               { // type contains a name
330                                                 a->type = removeRedundantWhiteSpace(g_curArgTypeName.left(i+1)).stripWhiteSpace();
331                                                 a->name = g_curArgTypeName.right(l-i-1).stripWhiteSpace();
332
333                                                 // if the type becomes a type specifier only then we make a mistake
334                                                 // and need to correct it to avoid seeing a nameless parameter
335                                                 // "struct A" as a parameter with type "struct" and name "A".
336                                                 int sv=0;
337                                                 if      (a->type.left(6)=="const ")    sv=6;
338                                                 else if (a->type.left(9)=="volatile ") sv=9;
339
340                                                 if (a->type.mid(sv)=="struct"    ||
341                                                     a->type.mid(sv)=="union"     ||
342                                                     a->type.mid(sv)=="class"     ||
343                                                     a->type.mid(sv)=="typename"  ||
344                                                     a->type=="const"             ||
345                                                     a->type=="volatile"
346                                                    )
347                                                 { 
348                                                   a->type = a->type + " " + a->name;
349                                                   a->name.resize(0);
350                                                 }
351                                                 //printf(" --> a->type='%s'\n",a->type.data());
352                                               }
353                                               else // assume only the type was specified, try to determine name later 
354                                               {
355                                                 a->type = removeRedundantWhiteSpace(g_curArgTypeName);  
356                                               }
357                                               if (!a->type.isEmpty() && a->type.at(0)=='$') // typeless PHP name?
358                                               {
359                                                 a->name = a->type;
360                                                 a->type = "";
361                                               }
362                                               a->array  += removeRedundantWhiteSpace(g_curArgArray);
363                                               //printf("array=%s\n",a->array.data());
364                                               int alen = a->array.length();
365                                               if (alen>2 && a->array.at(0)=='(' && 
366                                                             a->array.at(alen-1)==')') // fix-up for int *(a[10])
367                                               {
368                                                 int i=a->array.find('[')-1;
369                                                 a->array = a->array.mid(1,alen-2);
370                                                 if (i>0 && a->name.isEmpty())
371                                                 {
372                                                   a->name  = a->array.left(i).stripWhiteSpace();
373                                                   a->array = a->array.mid(i);
374                                                 }
375                                               }
376                                               a->defval = g_curArgDefValue.copy();
377                                               //printf("a->type=%s a->name=%s a->defval=\"%s\"\n",a->type.data(),a->name.data(),a->defval.data());
378                                               a->docs   = g_curArgDocs.stripWhiteSpace();
379                                               //printf("Argument `%s' `%s' adding docs=`%s'\n",a->type.data(),a->name.data(),a->docs.data());
380                                               g_argList->append(a);
381                                             }
382                                             g_curArgAttrib.resize(0);
383                                             g_curArgTypeName.resize(0);
384                                             g_curArgDefValue.resize(0);
385                                             g_curArgArray.resize(0);
386                                             g_curArgDocs.resize(0);
387                                             if (*yytext==')')
388                                             {
389                                               BEGIN(FuncQual);
390                                               //printf(">>> end of argument list\n");
391                                             }
392                                             else
393                                             {
394                                               BEGIN( ReadFuncArgType );
395                                             }
396                                           }
397                                         }
398 <ReadFuncArgType,ReadFuncArgPtr>"$"?{ID} { 
399                                           QCString name=yytext; //resolveDefines(yytext);
400                                           if (YY_START==ReadFuncArgType && g_curArgArray=="[]") // Java style array
401                                           {
402                                             g_curArgTypeName+=" []";
403                                             g_curArgArray.resize(0);
404                                           }
405                                           //printf("resolveName `%s'->`%s'\n",yytext,name.data());
406                                           g_curArgTypeName+=name;
407                                         }
408 <ReadFuncArgType,ReadFuncArgPtr>.       { 
409                                           g_curArgTypeName+=*yytext;
410                                         }
411
412 <ReadFuncArgDef,CopyArgString>"->"|">="|">>"    {
413                                           g_curArgDefValue+=yytext;
414                                         }
415 <ReadFuncArgDef,CopyArgString,CopyRawString>.           {
416                                           g_curArgDefValue+=*yytext;
417                                         }
418 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>{ID}  {
419                                           QCString name=yytext; //resolveDefines(yytext);
420                                           *g_copyArgValue+=name;
421                                         }
422 <CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>.  {
423                                           *g_copyArgValue += *yytext;
424                                         }
425 <FuncQual>"const"                       { 
426                                           g_argList->constSpecifier=TRUE;
427                                         }
428 <FuncQual>"volatile"                    { 
429                                           g_argList->volatileSpecifier=TRUE;
430                                         }
431 <FuncQual,TrailingReturn>"="{B}*"0"     { 
432                                           g_argList->pureSpecifier=TRUE;
433                                           BEGIN(FuncQual);
434                                         }
435 <FuncQual>"->"                          { // C++11 trailing return type
436                                           g_argList->trailingReturnType=" -> ";
437                                           BEGIN(TrailingReturn);
438                                         }
439 <TrailingReturn>{B}/("final"|"override"){B}*  {
440                                           unput(*yytext);
441                                           BEGIN(FuncQual);
442                                         }
443 <TrailingReturn>.                       {
444                                           g_argList->trailingReturnType+=yytext;
445                                         }
446 <TrailingReturn>\n                      {
447                                           g_argList->trailingReturnType+=yytext;
448                                         }
449 <FuncQual>")"{B}*"["[^]]*"]"            { // for functions returning a pointer to an array, 
450                                           // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]"
451                                           g_extraTypeChars=yytext;
452                                         }
453 <ReadDocBlock>[^\*\n]+                  {
454                                           g_curArgDocs+=yytext;
455                                         }
456 <ReadDocLine>[^\n]+                     {
457                                           g_curArgDocs+=yytext;
458                                         }
459 <ReadDocBlock>"*/"                      { 
460                                           if (g_lastDocChar!=0)
461                                             unput(g_lastDocChar);
462                                           BEGIN(g_lastDocContext); 
463                                         }
464 <ReadDocLine>\n                         {
465                                           if (g_lastDocChar!=0)
466                                             unput(g_lastDocChar);
467                                           BEGIN(g_lastDocContext);
468                                         }
469 <ReadDocBlock>\n                        {
470                                           g_curArgDocs+=*yytext;
471                                         }
472 <ReadDocBlock>.                         {
473                                           g_curArgDocs+=*yytext;
474                                         }
475 <*>("/*"[*!]|"//"[/!])("<"?)            {
476                                           g_lastDocContext=YY_START;
477                                           g_lastDocChar=0;  
478                                           if (yytext[1]=='/')
479                                             BEGIN( ReadDocLine );
480                                           else
481                                             BEGIN( ReadDocBlock );
482                                         }
483 <*>\n
484 <*>.
485
486 %%
487
488 /* ----------------------------------------------------------------------------
489  */
490
491 /*! Converts an argument string into an ArgumentList.
492  *  \param[in] argsString the list of Arguments.
493  *  \param[out] al a reference to resulting argument list pointer.
494  *  \param[out] extraTypeChars point to string to which trailing characters 
495  *              for complex types are written to
496  */
497  
498 void stringToArgumentList(const char *argsString,ArgumentList* al,QCString *extraTypeChars)
499 {
500   if (al==0) return; 
501   if (argsString==0) return;
502
503   g_copyArgValue=0;
504   g_curArgDocs.resize(0);
505   g_curArgAttrib.resize(0);
506   g_curArgArray.resize(0);
507   g_extraTypeChars.resize(0);
508   g_argRoundCount = 0;
509   g_argSharpCount = 0;
510   g_argCurlyCount = 0;
511   g_lastDocChar = 0;
512
513   g_inputString   = argsString;
514   g_inputPosition = 0;
515   g_curArgTypeName.resize(0);
516   g_curArgDefValue.resize(0);
517   g_curArgName.resize(0);
518   g_argList = al;
519   defargsYYrestart( defargsYYin );
520   BEGIN( Start );
521   defargsYYlex();
522   if (extraTypeChars) *extraTypeChars=g_extraTypeChars;
523   //printf("stringToArgumentList(%s) result=%s\n",argsString,argListToString(al).data());
524 }
525
526 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
527 extern "C" { // some bogus code to keep the compiler happy
528   void defargsYYdummy() { yy_flex_realloc(0,0); } 
529 }
530 #endif
531