1 /******************************************************************************
3 * $Id: pyscanner.l,v 1.9 2001/03/19 19:27:39 root Exp $
5 * Copyright (C) 1997-2012 by Dimitri van Heesch.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation under the terms of the GNU General Public License is hereby
9 * granted. No representations are made about the suitability of this software
10 * for any purpose. It is provided "as is" without express or implied warranty.
11 * See the GNU General Public License for more details.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
17 /* This code is based on the work done by the MoxyPyDoxy team
18 * (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada)
19 * in Spring 2005 as part of CS 179E: Compiler Design Project
20 * at the University of California, Riverside; the course was
21 * taught by Peter H. Froehlich <phf@acm.org>.
41 #include <qfileinfo.h>
43 #include "pyscanner.h"
51 #include "commentscan.h"
53 #include "arguments.h"
55 #define YY_NEVER_INTERACTIVE 1
58 /* -----------------------------------------------------------------
64 static ParserInterface *g_thisParser;
65 static const char * inputString;
66 static int inputPosition;
67 static QFile inputFile;
69 static Protection protection;
71 static Entry* current_root = 0 ;
72 static Entry* current = 0 ;
73 static Entry* previous = 0 ;
74 static Entry* bodyEntry = 0 ;
75 static int yyLineNr = 1 ;
76 static QCString yyFileName;
77 static MethodTypes mtype;
79 static Specifier virt;
81 static int docBlockContext;
82 static QCString docBlock;
83 static QCString docBlockName;
84 static bool docBlockInBody;
85 static bool docBlockJavaStyle;
87 static bool docBlockSpecial;
89 static bool g_doubleQuote;
90 static bool g_specialBlock;
91 static int g_stringContext;
92 static QGString * g_copyString;
93 static int g_indent = 0;
94 static int g_curIndent = 0;
96 static QDict<QCString> g_packageNameCache(257);
97 static QCString g_packageScope;
99 static char g_atomStart;
100 static char g_atomEnd;
101 static int g_atomCount;
103 //static bool g_insideConstructor;
105 static QCString g_moduleScope;
106 static QCString g_packageName;
108 //static bool g_hideClassDocs;
110 static QCString g_defVal;
111 static int g_braceCount;
113 static bool g_lexInit = FALSE;
114 static bool g_packageCommentAllowed;
116 //-----------------------------------------------------------------------------
119 static void initParser()
126 g_packageCommentAllowed = TRUE;
127 g_packageNameCache.setAutoDelete(TRUE);
130 static void initEntry()
132 //current->python = TRUE;
133 current->protection = protection ;
134 current->mtype = mtype;
135 current->virt = virt;
136 current->stat = gstat;
137 current->lang = SrcLangExt_Python;
138 current->setParent(current_root);
139 initGroupInfo(current);
143 static void newEntry()
146 current_root->addSubEntry(current);
147 current = new Entry ;
151 static void newVariable()
153 if (!current->name.isEmpty() && current->name.at(0)=='_') // mark as private
155 current->protection=Private;
157 if (current_root->section&Entry::COMPOUND_MASK) // mark as class variable
159 current->stat = TRUE;
164 static void newFunction()
166 if (current->name.left(2)=="__" && current->name.right(2)=="__")
168 // special method name, see
169 // http://docs.python.org/ref/specialnames.html
170 current->protection=Public;
172 else if (current->name.at(0)=='_')
174 current->protection=Private;
178 static inline int computeIndent(const char *s)
181 static int tabSize=Config_getInt("TAB_SIZE");
187 else if (c=='\t') col+=tabSize-(col%tabSize);
193 static QCString findPackageScopeFromPath(const QCString &path)
195 QCString *pScope = g_packageNameCache.find(path);
200 QFileInfo pf(path+"/__init__.py"); // found package initialization file
203 int i=path.findRev('/');
206 QCString scope = findPackageScopeFromPath(path.left(i));
207 if (!scope.isEmpty())
211 scope+=path.mid(i+1);
212 g_packageNameCache.insert(path,new QCString(scope));
219 static QCString findPackageScope(const char *fileName)
221 if (fileName==0) return "";
222 QFileInfo fi(fileName);
223 return findPackageScopeFromPath(fi.dirPath(TRUE).data());
226 //-----------------------------------------------------------------------------
228 static void lineCount()
230 //fprintf(stderr,"yyLineNr=%d\n",yyLineNr);
231 for (const char *p = yytext; *p; ++p)
233 yyLineNr += (*p == '\n') ;
237 static void incLineNr()
239 //fprintf(stderr,"yyLineNr=%d\n",yyLineNr);
244 // Appends the current-name to current-type;
245 // Destroys current-name.
246 // Destroys current->args and current->argList
247 static void addType( Entry* current )
249 uint tl=current->type.length();
250 if ( tl>0 && !current->name.isEmpty() && current->type.at(tl-1)!='.')
252 current->type += ' ' ;
254 current->type += current->name ;
255 current->name.resize(0) ;
256 tl=current->type.length();
257 if ( tl>0 && !current->args.isEmpty() && current->type.at(tl-1)!='.')
259 current->type += ' ' ;
261 current->type += current->args ;
262 current->args.resize(0) ;
263 current->argList->clear();
266 static QCString stripQuotes(const char *s)
269 if (s==0 || *s==0) return name;
271 if (name.at(0)=='"' && name.at(name.length()-1)=='"')
273 name=name.mid(1,name.length()-2);
278 //-----------------------------------------------------------------
280 //-----------------------------------------------------------------
281 static void startCommentBlock(bool brief)
285 current->briefFile = yyFileName;
286 current->briefLine = yyLineNr;
290 current->docFile = yyFileName;
291 current->docLine = yyLineNr;
296 static void appendDocBlock() {
298 current_root->addSubEntry(current);
304 static void handleCommentBlock(const QCString &doc,bool brief)
306 //printf("handleCommentBlock(doc=[%s] brief=%d docBlockInBody=%d docBlockJavaStyle=%d\n",
307 // doc.data(),brief,docBlockInBody,docBlockJavaStyle);
310 docBlockInBody=FALSE;
312 if (docBlockInBody && previous && !previous->doc.isEmpty())
314 previous->doc=previous->doc.stripWhiteSpace()+"\n\n";
319 int lineNr = brief ? current->briefLine : current->docLine;
320 while (parseCommentBlock(
322 (docBlockInBody && previous) ? previous : current,
326 docBlockInBody ? FALSE : brief,
327 docBlockJavaStyle, // javadoc style // or FALSE,
332 ) // need to start a new entry
346 static void endOfDef(int correction=0)
348 //printf("endOfDef at=%d\n",yyLineNr);
351 bodyEntry->endBodyLine = yyLineNr-correction;
355 //g_insideConstructor = FALSE;
358 static inline void addToString(const char *s)
360 if (g_copyString) (*g_copyString)+=s;
363 static void initTriDoubleQuoteBlock()
365 docBlockContext = YY_START;
366 docBlockInBody = FALSE;
367 docBlockJavaStyle = TRUE;
368 docBlockSpecial = yytext[3]=='!';
370 g_doubleQuote = TRUE;
371 startCommentBlock(FALSE);
374 static void initTriSingleQuoteBlock()
376 docBlockContext = YY_START;
377 docBlockInBody = FALSE;
378 docBlockJavaStyle = TRUE;
379 docBlockSpecial = yytext[3]=='!';
381 g_doubleQuote = FALSE;
382 startCommentBlock(FALSE);
385 static void initSpecialBlock()
387 docBlockContext = YY_START;
388 docBlockInBody = FALSE;
389 docBlockJavaStyle = TRUE;
392 startCommentBlock(TRUE);
395 static void searchFoundDef()
397 current->fileName = yyFileName;
398 current->startLine = yyLineNr;
399 current->bodyLine = yyLineNr;
400 current->section = Entry::FUNCTION_SEC;
401 current->protection = protection = Public;
402 current->lang = SrcLangExt_Python;
403 current->virt = Normal;
404 current->stat = gstat;
405 current->mtype = mtype = Method;
406 current->type.resize(0);
407 current->name.resize(0);
408 current->args.resize(0);
409 current->argList->clear();
410 g_packageCommentAllowed = FALSE;
412 //printf("searchFoundDef at=%d\n",yyLineNr);
415 static void searchFoundClass()
417 current->section = Entry::CLASS_SEC;
418 current->argList->clear();
419 current->type += "class" ;
420 current->fileName = yyFileName;
421 current->startLine = yyLineNr;
422 current->bodyLine = yyLineNr;
423 g_packageCommentAllowed = FALSE;
426 //-----------------------------------------------------------------------------
427 /* ----------------------------------------------------------------- */
429 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
431 static int yyread(char *buf,int max_size)
434 while ( c < max_size && inputString[inputPosition] )
436 *buf = inputString[inputPosition++] ;
437 //printf("%d (%c)\n",*buf,*buf);
445 /* start command character */
456 HEXNUMBER "0"[xX][0-9a-fA-F]+[lL]?
457 OCTNUMBER "0"[0-7]+[lL]?
458 NUMBER {DIGIT}+[lLjJ]?
459 INTNUMBER {HEXNUMBER}|{OCTNUMBER}|{NUMBER}
460 FLOATNUMBER {DIGIT}+"."{DIGIT}+([eE][+\-]?{DIGIT}+)?[jJ]?
462 NONEMPTY [A-Za-z0-9_]
463 EXPCHAR [#(){}\[\],:.%/\\=`*~|&<>!;+-]
464 NONEMPTYEXP [^ \t\n:]
465 PARAMNONEMPTY [^ \t\n():]
466 IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")*
467 SCOPE {IDENTIFIER}("."{IDENTIFIER})*
468 BORDER ([^A-Za-z0-9])
470 TRISINGLEQUOTE "'''"(!)?
471 TRIDOUBLEQUOTE "\"\"\""(!)?
472 LONGSTRINGCHAR [^\\"']
474 LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ})
475 SMALLQUOTE ("\"\""|"\""|"'"|"''")
476 LONGSTRINGBLOCK ({LONGSTRINGITEM}+|{SMALLQUOTE})
478 SHORTSTRING ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"')
479 SHORTSTRINGITEM ({SHORTSTRINGCHAR}|{ESCAPESEQ})
480 SHORTSTRINGCHAR [^\\\n"]
481 STRINGLITERAL {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING})
482 STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR")
483 KEYWORD ("lambda"|"import"|"class"|"assert"|"as"|"from"|"global"|"def"|"True"|"False")
484 FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally")
485 POUNDCOMMENT "#"[^#\n][^\n]*
491 /* Main start state */
496 /* Mid-comment states */
498 /* %x FuncDoubleComment */
499 /* %x ClassDoubleComment */
504 /* Function states */
509 %x FunctionParamDefVal
515 %x ClassCaptureIndent
518 /* Variable states */
536 /* ------------ Function recognition rules -------------- */
540 ^{B}"def"{BB} { // start of a function/method definition with indent
541 //fprintf(stderr,"Found def at %d\n",yyLineNr);
542 g_indent=computeIndent(yytext);
544 BEGIN( FunctionDec );
546 "def"{BB} { // start of a function/method definition
548 BEGIN( FunctionDec );
551 ^{B}"class"{BB} { // start of a class definition with indent
552 //fprintf(stderr,"Found class at %d\n",yyLineNr);
553 g_indent=computeIndent(yytext);
557 "class"{BB} { // start of a class definition
562 "from"{BB} { // start of an from import
563 g_packageCommentAllowed = FALSE;
568 "import"{BB} { // start of an import statement
569 g_packageCommentAllowed = FALSE;
572 ^{B}{IDENTIFIER}/{B}"="{B}"property" { // property
573 current->section = Entry::VARIABLE_SEC;
574 current->mtype = Property;
575 current->name = QCString(yytext).stripWhiteSpace();
576 current->fileName = yyFileName;
577 current->startLine = yyLineNr;
578 current->bodyLine = yyLineNr;
579 g_packageCommentAllowed = FALSE;
582 ^{B}{IDENTIFIER}/{B}"="[^=] { // variable
583 g_indent=computeIndent(yytext);
584 current->section = Entry::VARIABLE_SEC;
585 current->name = QCString(yytext).stripWhiteSpace();
586 current->fileName = yyFileName;
587 current->startLine = yyLineNr;
588 current->bodyLine = yyLineNr;
589 g_packageCommentAllowed = FALSE;
592 "'" { // start of a single quoted string
593 g_stringContext=YY_START;
595 g_packageCommentAllowed = FALSE;
596 BEGIN( SingleQuoteString );
598 "\"" { // start of a double quoted string
599 g_stringContext=YY_START;
601 g_packageCommentAllowed = FALSE;
602 BEGIN( DoubleQuoteString );
607 {POUNDCOMMENT} { // normal comment
608 g_packageCommentAllowed = FALSE;
610 {IDENTIFIER} { // some other identifier
611 g_packageCommentAllowed = FALSE;
614 g_curIndent=computeIndent(yytext);
617 {NEWLINE}+ { // new line
621 {TRIDOUBLEQUOTE} { // start of a comment block
622 initTriDoubleQuoteBlock();
623 BEGIN(TripleComment);
626 {TRISINGLEQUOTE} { // start of a comment block
627 initTriSingleQuoteBlock();
628 BEGIN(TripleComment);
631 {STARTDOCSYMS}/[^#] { // start of a special comment
632 g_curIndent=computeIndent(yytext);
633 g_packageCommentAllowed = FALSE;
635 BEGIN(SpecialComment);
637 [^\n] { // any other character...
638 // This is the major default
639 // that should catch everything
645 {IDENTIFIER}({B}"."{B}{IDENTIFIER})* { // from package import
646 g_packageName=yytext;
665 QCString item=g_packageName;
666 current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
667 current->fileName = yyFileName;
668 //printf("Adding using directive: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
669 current->section=Entry::USINGDIR_SEC;
670 current_root->addSubEntry(current);
671 current = new Entry ;
675 {IDENTIFIER}/{B}","{B} {
676 QCString item=g_packageName+"."+yytext;
677 current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
678 current->fileName = yyFileName;
679 //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
680 current->section=Entry::USINGDECL_SEC;
681 current_root->addSubEntry(current);
682 current = new Entry ;
686 QCString item=g_packageName+"."+yytext;
687 current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
688 current->fileName = yyFileName;
689 //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
690 current->section=Entry::USINGDECL_SEC;
691 current_root->addSubEntry(current);
692 current = new Entry ;
711 {IDENTIFIER}({B}"."{B}{IDENTIFIER})* {
712 current->name=removeRedundantWhiteSpace(substitute(yytext,".","::"));
713 current->fileName = yyFileName;
714 //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
715 current->section=Entry::USINGDECL_SEC;
716 current_root->addSubEntry(current);
717 current = new Entry ;
734 "self."{IDENTIFIER}/{B}"=" {
735 //fprintf(stderr,"Found member variable %s in %s at %d\n",&yytext[5],current_root->name.data(),yyLineNr);
736 current->name=&yytext[5];
737 current->section=Entry::VARIABLE_SEC;
738 current->fileName = yyFileName;
739 current->startLine = yyLineNr;
740 current->bodyLine = yyLineNr;
741 current->type.resize(0);
742 if (current->name.at(0)=='_') // mark as private
744 current->protection=Private;
748 current->protection=Public;
752 {TRIDOUBLEQUOTE} { // start of a comment block
753 initTriDoubleQuoteBlock();
754 BEGIN(TripleComment);
757 {TRISINGLEQUOTE} { // start of a comment block
758 initTriSingleQuoteBlock();
759 BEGIN(TripleComment);
762 {STARTDOCSYMS}/[^#] { // start of a special comment
764 BEGIN(SpecialComment);
766 {POUNDCOMMENT} { // #
768 "'" { // start of a single quoted string
769 g_stringContext=YY_START;
771 BEGIN( SingleQuoteString );
773 "\"" { // start of a double quoted string
774 g_stringContext=YY_START;
776 BEGIN( DoubleQuoteString );
779 {IDENTIFIER} // identifiers
780 [^'"\.#a-z_A-Z\n]+ // other uninteresting stuff
785 \n{B}/{IDENTIFIER}{BB} {
786 //fprintf(stderr,"indent %d<=%d\n",computeIndent(&yytext[1]),g_indent);
787 if (computeIndent(&yytext[1])<=g_indent)
790 for (i=yyleng-1;i>=0;i--)
795 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
801 current->program+=yytext;
805 if (computeIndent(&yytext[1])<=g_indent)
808 for (i=yyleng-1;i>=0;i--)
813 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
819 current->program+=yytext;
826 ^{BB}/\n { // skip empty line
827 current->program+=yytext;
829 ^{BB} { // something at indent >0
830 current->program+=yytext;
831 g_curIndent = computeIndent(yytext);
832 if (g_curIndent<=g_indent)
833 // jumped out of the function
839 "'" { // start of a single quoted string
840 current->program+=yytext;
841 g_stringContext=YY_START;
842 g_specialBlock = FALSE;
843 g_copyString=¤t->program;
844 BEGIN( SingleQuoteString );
846 "\"" { // start of a double quoted string
847 current->program+=yytext;
848 g_stringContext=YY_START;
849 g_specialBlock = FALSE;
850 g_copyString=¤t->program;
851 BEGIN( DoubleQuoteString );
853 [^ \t\n#'".]+ { // non-special stuff
854 current->program+=yytext;
855 g_specialBlock = FALSE;
857 ^{POUNDCOMMENT} { // normal comment
858 current->program+=yytext;
860 "#".* { // comment half way
861 current->program+=yytext;
865 current->program+=yytext;
868 current->program+=*yytext;
869 g_specialBlock = FALSE;
872 {TRIDOUBLEQUOTE} { // start of a comment block
873 current->program+=yytext;
874 initTriDoubleQuoteBlock();
875 BEGIN(TripleComment);
878 {TRISINGLEQUOTE} { // start of a comment block
879 current->program+=yytext;
880 initTriSingleQuoteBlock();
881 BEGIN(TripleComment);
884 {STARTDOCSYMS}/[^#] { // start of a special comment
886 BEGIN(SpecialComment);
894 //found function name
895 if (current->type.isEmpty())
897 current->type = "def";
899 current->name = yytext;
900 current->name = current->name.stripWhiteSpace();
903 {B}":" { // function without arguments
904 g_specialBlock = TRUE; // expecting a docstring
906 current->bodyLine = yyLineNr;
907 BEGIN( FunctionBody );
911 BEGIN( FunctionParams );
919 {IDENTIFIER} { // Name of parameter
921 Argument *a = new Argument;
922 current->argList->append(a);
923 current->argList->getLast()->name = QCString(yytext).stripWhiteSpace();
924 current->argList->getLast()->type = "";
926 "=" { // default value
927 // TODO: this rule is too simple, need to be able to
928 // match things like =")" as well!
929 QCString defVal=&yytext[1];
932 BEGIN(FunctionParamDefVal);
935 ")" { // end of parameter list
939 g_specialBlock = TRUE; // expecting a docstring
941 current->bodyLine = yyLineNr;
942 BEGIN( FunctionBody );
944 {POUNDCOMMENT} { // a comment
946 {PARAMNONEMPTY} { // Default rule inside arguments.
951 <FunctionParamDefVal>{
952 "(" { // internal opening brace
958 if (g_braceCount==0) // end of default argument
960 if (current->argList->getLast())
962 current->argList->getLast()->defval=g_defVal.stripWhiteSpace();
964 BEGIN(FunctionParams);
983 \n/{IDENTIFIER}{BB} { // new def at indent 0
986 //g_hideClassDocs = FALSE;
987 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
990 \n/"##"[^#] { // start of a special comment at indent 0
993 //g_hideClassDocs = FALSE;
994 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
997 ^{BB}/\n { // skip empty line
998 current->program+=yytext;
1004 ^{BB} { // something at indent >0
1005 g_curIndent=computeIndent(yytext);
1006 //fprintf(stderr,"g_curIndent=%d g_indent=%d\n",g_curIndent,g_indent);
1007 if (g_curIndent<=g_indent)
1008 // jumped out of the class/method
1011 g_indent=g_curIndent;
1012 // make sure the next rule matches ^...
1013 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
1014 //g_hideClassDocs = FALSE;
1019 current->program+=yytext;
1022 "'" { // start of a single quoted string
1023 current->program+=*yytext;
1024 g_stringContext=YY_START;
1025 g_specialBlock = FALSE;
1026 g_copyString=¤t->program;
1027 BEGIN( SingleQuoteString );
1029 "\"" { // start of a double quoted string
1030 current->program+=*yytext;
1031 g_stringContext=YY_START;
1032 g_specialBlock = FALSE;
1033 g_copyString=¤t->program;
1034 BEGIN( DoubleQuoteString );
1036 [^ \t\n#'"]+ { // non-special stuff
1037 current->program+=yytext;
1038 g_specialBlock = FALSE;
1039 //g_hideClassDocs = FALSE;
1042 current->program+=*yytext;
1045 {POUNDCOMMENT} { // normal comment
1046 current->program+=yytext;
1048 . { // any character
1049 g_specialBlock = FALSE;
1050 current->program+=*yytext;
1052 {TRIDOUBLEQUOTE} { // start of a comment block
1053 //if (!g_hideClassDocs)
1054 current->program+=yytext;
1055 initTriDoubleQuoteBlock();
1056 BEGIN(TripleComment);
1059 {TRISINGLEQUOTE} { // start of a comment block
1060 //if (!g_hideClassDocs)
1061 current->program+=yytext;
1062 initTriSingleQuoteBlock();
1063 BEGIN(TripleComment);
1067 <ClassDec>{IDENTIFIER} {
1068 if (current->type.isEmpty())
1070 current->type = "class";
1073 current->section = Entry::CLASS_SEC;
1074 current->name = yytext;
1076 // prepend scope in case of nested classes
1077 if (current_root->section&Entry::SCOPE_MASK)
1079 //printf("*** Prepending scope %s to class %s\n",current_root->name.data(),current->name.data());
1080 current->name.prepend(current_root->name+"::");
1083 current->name = current->name.stripWhiteSpace();
1084 current->fileName = yyFileName;
1085 docBlockContext = YY_START;
1086 docBlockInBody = FALSE;
1087 docBlockJavaStyle = FALSE;
1090 BEGIN(ClassInheritance);
1094 ({BB}|[\(,\)]) { // syntactic sugar for the list
1097 ":" { // begin of the class definition
1098 g_specialBlock = TRUE; // expecting a docstring
1099 current->bodyLine = yyLineNr;
1100 current->program.resize(0);
1101 BEGIN(ClassCaptureIndent);
1105 current->extends->append(
1106 new BaseInfo(substitute(yytext,".","::"),Public,Normal)
1108 //Has base class-do stuff
1113 <ClassCaptureIndent>{
1115 // Blankline - ignore, keep looking for indentation.
1117 current->program+=yytext;
1120 {TRIDOUBLEQUOTE} { // start of a comment block
1121 initTriDoubleQuoteBlock();
1122 current->program+=yytext;
1123 BEGIN(TripleComment);
1126 {TRISINGLEQUOTE} { // start of a comment block
1127 initTriSingleQuoteBlock();
1128 current->program+=yytext;
1129 BEGIN(TripleComment);
1133 current->program+=yytext;
1134 //current->startLine = yyLineNr;
1135 g_curIndent=computeIndent(yytext);
1136 bodyEntry = current;
1137 //fprintf(stderr,"setting indent %d\n",g_curIndent);
1138 //printf("current->program=[%s]\n",current->program.data());
1139 //g_hideClassDocs = TRUE;
1143 ""/({NONEMPTY}|{EXPCHAR}) {
1145 // Just pushback an empty class, and
1146 // resume parsing the body.
1148 current->program+=yytext;
1150 // printf("Failed to find indent - skipping!");
1157 "=" { // the assignment operator
1158 //printf("====== VariableDec at line %d\n",yyLineNr);
1162 {INTNUMBER} { // integer value
1163 current->type = "int";
1164 current->initializer = yytext;
1167 {FLOATNUMBER} { // floating point value
1168 current->type = "float";
1169 current->initializer = yytext;
1172 {STRINGPREFIX}?"'" { // string
1173 current->type = "string";
1174 current->initializer = yytext;
1175 g_copyString=¤t->initializer;
1176 g_stringContext=VariableEnd;
1177 BEGIN( SingleQuoteString );
1179 {STRINGPREFIX}?"\"" { // string
1180 current->type = "string";
1181 current->initializer = yytext;
1182 g_copyString=¤t->initializer;
1183 g_stringContext=VariableEnd;
1184 BEGIN( DoubleQuoteString );
1186 {TRIDOUBLEQUOTE} { // start of a comment block
1187 current->type = "string";
1188 current->initializer = yytext;
1190 g_copyString=¤t->initializer;
1191 g_stringContext=VariableEnd;
1192 BEGIN(TripleString);
1195 {TRISINGLEQUOTE} { // start of a comment block
1196 current->type = "string";
1197 current->initializer = yytext;
1198 g_doubleQuote=FALSE;
1199 g_copyString=¤t->initializer;
1200 g_stringContext=VariableEnd;
1201 BEGIN(TripleString);
1204 if (current->mtype!=Property)
1206 current->type = "tuple";
1208 current->initializer+=*yytext;
1212 BEGIN( VariableAtom );
1215 current->type = "list";
1216 current->initializer+=*yytext;
1220 BEGIN( VariableAtom );
1223 current->type = "dictionary";
1224 current->initializer+=*yytext;
1228 BEGIN( VariableAtom );
1231 BEGIN( VariableEnd );
1234 current->initializer+=yytext;
1237 current->initializer+=*yytext;
1241 BEGIN( VariableEnd );
1247 current->initializer+=*yytext;
1248 if (g_atomStart==*yytext)
1254 current->initializer+=*yytext;
1255 if (g_atomEnd==*yytext)
1265 g_stringContext=YY_START;
1266 current->initializer+="\"";
1267 g_copyString=¤t->initializer;
1268 BEGIN( DoubleQuoteString );
1271 current->initializer+=yytext;
1274 current->initializer+=*yytext;
1277 current->initializer+=*yytext;
1294 <<EOF>> { yyterminate();
1302 // printf("Expected module block %d special=%d\n",g_expectModuleDocs,g_specialBlock);
1303 if (g_doubleQuote==(yytext[0]=='"'))
1305 if (g_specialBlock) // expecting a docstring
1307 QCString actualDoc=docBlock;
1308 if (!docBlockSpecial) // legacy unformatted docstring
1310 actualDoc.prepend("\\verbatim ");
1311 actualDoc.append("\\endverbatim ");
1313 //printf("-------> current=%p bodyEntry=%p\n",current,bodyEntry);
1314 handleCommentBlock(actualDoc, FALSE);
1316 else if (g_packageCommentAllowed) // expecting module docs
1318 QCString actualDoc=docBlock;
1319 if (!docBlockSpecial) // legacy unformatted docstring
1321 actualDoc.prepend("\\verbatim ");
1322 actualDoc.append("\\endverbatim ");
1324 actualDoc.prepend("\\namespace "+g_moduleScope+"\\_linebr ");
1325 handleCommentBlock(actualDoc, FALSE);
1327 if ((docBlockContext==ClassBody /*&& !g_hideClassDocs*/) ||
1328 docBlockContext==FunctionBody)
1330 current->program+=docBlock;
1331 current->program+=yytext;
1333 //if (g_hideClassDocs)
1335 // current->startLine = yyLineNr;
1337 //g_hideClassDocs=FALSE;
1338 BEGIN(docBlockContext);
1344 g_packageCommentAllowed = FALSE;
1348 ^{BB} { // leading whitespace
1349 int indent = computeIndent(yytext);
1350 if (indent>=g_curIndent)
1351 { // strip g_curIndent amount of whitespace
1353 for (i=0;i<indent-g_curIndent;i++) docBlock+=' ';
1354 //fprintf(stderr,"stripping indent %d\n",g_curIndent);
1358 //fprintf(stderr,"not stripping: %d<%d\n",indent,g_curIndent);
1375 ^{B}"#"("#")* { // skip leading hashes
1377 \n/{B}"#" { // continuation of the comment on the next line
1380 startCommentBlock(FALSE);
1383 [^#\n]+ { // any other stuff
1386 \n { // new line that ends the comment
1387 handleCommentBlock(docBlock, docBrief);
1389 BEGIN(docBlockContext);
1391 . { // anything we missed
1396 <SingleQuoteString>{
1397 \\{B}\n { // line continuation
1398 addToString(yytext);
1401 \\. { // espaced char
1402 addToString(yytext);
1404 "\"\"\"" { // tripple double quotes
1405 addToString(yytext);
1407 "'" { // end of the string
1408 addToString(yytext);
1409 BEGIN(g_stringContext);
1411 [^"'\n\\]+ { // normal chars
1412 addToString(yytext);
1415 addToString(yytext);
1419 <DoubleQuoteString>{
1420 \\{B}\n { // line continuation
1421 addToString(yytext);
1424 \\. { // espaced char
1425 addToString(yytext);
1427 "'''" { // tripple single quotes
1428 addToString(yytext);
1430 "\"" { // end of the string
1431 addToString(yytext);
1432 BEGIN(g_stringContext);
1434 [^"'\n\\]+ { // normal chars
1435 addToString(yytext);
1438 addToString(yytext);
1445 *g_copyString += yytext;
1446 if (g_doubleQuote==(yytext[0]=='"'))
1448 BEGIN(g_stringContext);
1453 ({LONGSTRINGBLOCK}) {
1455 *g_copyString += yytext;
1459 *g_copyString += yytext;
1462 *g_copyString += *yytext;
1466 /* ------------ End rules -------------- */
1469 <*>({NONEMPTY}|{EXPCHAR}|{BB}) { // This should go one character at a time.
1470 // printf("[pyscanner] '%s' [ state %d ] [line %d] no match\n",
1471 // yytext, YY_START, yyLineNr);
1477 //printf("[pyscanner] %d NEWLINE [line %d] no match\n",
1478 // YY_START, yyLineNr);
1484 //printf("[pyscanner] '%s' [ state %d ] [line %d] no match\n",
1485 // yytext, YY_START, yyLineNr);
1492 //----------------------------------------------------------------------------
1494 static void parseCompounds(Entry *rt)
1496 //printf("parseCompounds(%s)\n",rt->name.data());
1497 EntryListIterator eli(*rt->children());
1499 for (;(ce=eli.current());++eli)
1501 if (!ce->program.isEmpty())
1503 //printf("-- %s ---------\n%s\n---------------\n",
1504 // ce->name.data(),ce->program.data());
1505 // init scanner state
1506 inputString = ce->program;
1508 pyscanYYrestart( pyscanYYin ) ;
1509 if (ce->section&Entry::COMPOUND_MASK)
1514 else if (ce->parent())
1516 current_root = ce->parent();
1517 //printf("Searching for member variables in %s parent=%s\n",
1518 // ce->name.data(),ce->parent->name.data());
1519 BEGIN( SearchMemVars );
1521 yyFileName = ce->fileName;
1522 yyLineNr = ce->bodyLine ;
1523 if (current) delete current;
1524 current = new Entry;
1527 groupEnterCompound(yyFileName,yyLineNr,ce->name);
1531 delete current; current=0;
1532 ce->program.resize(0);
1534 groupLeaveCompound(yyFileName,yyLineNr,ce->name);
1541 //----------------------------------------------------------------------------
1544 static void parseMain(const char *fileName,const char *fileBuf,Entry *rt)
1548 inputString = fileBuf;
1551 protection = Public;
1556 g_specialBlock = FALSE;
1559 inputFile.setName(fileName);
1560 if (inputFile.open(IO_ReadOnly))
1563 yyFileName = fileName;
1565 msg("Parsing file %s...\n",yyFileName.data());
1567 QFileInfo fi(fileName);
1568 g_moduleScope = findPackageScope(fileName);
1569 QCString baseName=fi.baseName().utf8();
1570 if (baseName!="__init__") // package initializer file is not a package itself
1572 if (!g_moduleScope.isEmpty())
1574 g_moduleScope+="::";
1576 g_moduleScope+=baseName;
1579 current = new Entry;
1581 current->name = g_moduleScope;
1582 current->section = Entry::NAMESPACE_SEC;
1583 current->type = "namespace";
1584 current->fileName = yyFileName;
1585 current->startLine = yyLineNr;
1586 current->bodyLine = yyLineNr;
1588 rt->addSubEntry(current);
1590 current_root = current ;
1592 current = new Entry;
1594 groupEnterFile(yyFileName,yyLineNr);
1598 pyscanYYrestart( pyscanYYin );
1603 groupLeaveFile(yyFileName,yyLineNr);
1605 current_root->program.resize(0);
1606 delete current; current=0;
1608 parseCompounds(current_root);
1615 //----------------------------------------------------------------------------
1617 static void parsePrototype(const QCString &text)
1619 //printf("**** parsePrototype(%s) begin\n",text.data());
1622 warn(yyFileName,yyLineNr,"Empty prototype found!");
1626 g_specialBlock = FALSE;
1627 g_packageCommentAllowed = FALSE;
1629 const char *orgInputString;
1630 int orgInputPosition;
1631 YY_BUFFER_STATE orgState;
1633 // save scanner state
1634 orgState = YY_CURRENT_BUFFER;
1635 yy_switch_to_buffer(yy_create_buffer(pyscanYYin, YY_BUF_SIZE));
1636 orgInputString = inputString;
1637 orgInputPosition = inputPosition;
1642 pyscanYYrestart( pyscanYYin );
1644 BEGIN( FunctionDec );
1649 current->name = current->name.stripWhiteSpace();
1650 if (current->section == Entry::MEMBERDOC_SEC && current->args.isEmpty())
1651 current->section = Entry::VARIABLEDOC_SEC;
1653 // restore original scanner state
1655 YY_BUFFER_STATE tmpBuf = YY_CURRENT_BUFFER;
1656 yy_switch_to_buffer(orgState);
1657 yy_delete_buffer(tmpBuf);
1659 inputString = orgInputString;
1660 inputPosition = orgInputPosition;
1662 //printf("**** parsePrototype end\n");
1665 void pyscanFreeScanner()
1667 #if defined(YY_FLEX_SUBMINOR_VERSION)
1670 pyscanYYlex_destroy();
1675 //----------------------------------------------------------------------------
1677 void PythonLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root)
1679 g_thisParser = this;
1680 ::parseMain(fileName,fileBuf,root);
1682 // May print the AST for debugging purposes
1683 // printAST(global_root);
1686 bool PythonLanguageScanner::needsPreprocessing(const QCString &)
1691 void PythonLanguageScanner::parseCode(CodeOutputInterface &codeOutIntf,
1692 const char *scopeName,
1693 const QCString &input,
1694 bool isExampleBlock,
1695 const char *exampleName,
1699 bool inlineFragment,
1700 MemberDef *memberDef,
1701 bool showLineNumbers,
1702 Definition *searchCtx
1705 ::parsePythonCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
1706 fileDef,startLine,endLine,inlineFragment,memberDef,
1707 showLineNumbers,searchCtx);
1710 void PythonLanguageScanner::parsePrototype(const char *text)
1712 ::parsePrototype(text);
1716 void PythonLanguageScanner::resetCodeParserState()
1718 ::resetPythonCodeParserState();
1721 //----------------------------------------------------------------------------
1723 #if !defined(YY_FLEX_SUBMINOR_VERSION)
1724 //----------------------------------------------------------------------------
1725 extern "C" { // some bogus code to keep the compiler happy
1726 void pyscannerYYdummy() { yy_flex_realloc(0,0); }