From 05547d571d1f5c32e7577ef26c830a240505d0aa Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Sat, 5 Sep 2020 19:17:07 +0200 Subject: Refactoring: making pycode.l reentrant --- src/code.l | 41 +- src/pycode.h | 13 +- src/pycode.l | 2405 ++++++++++++++++++++++++++++--------------------------- src/pyscanner.l | 7 +- 4 files changed, 1260 insertions(+), 1206 deletions(-) diff --git a/src/code.l b/src/code.l index 04f4bd5..e731392 100644 --- a/src/code.l +++ b/src/code.l @@ -1,8 +1,6 @@ /****************************************************************************** * - * - * - * Copyright (C) 1997-2015 by Dimitri van Heesch. + * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby @@ -32,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -127,8 +127,6 @@ class VariableContext void addVariable(yyscan_t yyscanner,const QCString &type,const QCString &name); const ClassDef *findVariable(const QCString &name); - size_t size() const { return m_scopes.size(); } - private: Scope m_globalScope; std::vector m_scopes; @@ -141,7 +139,7 @@ class CallContext public: struct Ctx { - Ctx(QCString _name, QCString _type) : name(_name), type(_type) {} + Ctx(QCString name_, QCString type_) : name(name_), type(type_) {} QCString name; QCString type; const Definition *d = 0; @@ -158,19 +156,19 @@ class CallContext DBG_CTX((stderr,"** Set call context %s (%p)\n",d==0 ? "" : d->name().data(),d)); ctx.d=d; } - void pushScope(QCString _name, QCString _type) + void pushScope(QCString name_, QCString type_) { - m_defList.push_back(Ctx(_name,_type)); + m_defList.push_back(Ctx(name_,type_)); DBG_CTX((stderr,"** Push call context %zu\n",m_defList.size())); } - void popScope(QCString &_name, QCString &_type) + void popScope(QCString &name_, QCString &type_) { if (m_defList.size()>1) { DBG_CTX((stderr,"** Pop call context %zu\n",m_defList.size())); const Ctx &ctx = m_defList.back(); - _name = ctx.name; - _type = ctx.type; + name_ = ctx.name; + type_ = ctx.type; m_defList.pop_back(); } else @@ -2379,13 +2377,12 @@ const ClassDef *VariableContext::findVariable(const QCString &name) { if (name.isEmpty()) return 0; const ClassDef *result = 0; - QCString key = name; - // search from inner to outer scope + // search from inner to outer scope auto it = std::rbegin(m_scopes); while (it != std::rend(m_scopes)) { - auto it2 = it->find(key.str()); + auto it2 = it->find(name.str()); if (it2 != std::end(*it)) { result = it2->second; @@ -2396,7 +2393,7 @@ const ClassDef *VariableContext::findVariable(const QCString &name) } // nothing found -> also try the global scope auto it2 = m_globalScope.find(name.str()); - if (it2!=m_globalScope.end()) + if (it2 != m_globalScope.end()) { result = it2->second; } @@ -3422,18 +3419,14 @@ static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,cons { ccd = it->second.get(); } - if (ccd) + if (ccd && ccd->baseClasses()) { - //printf("using classScope %s\n",yyextra->classScope.data()); - if (ccd->baseClasses()) + BaseClassListIterator bcli(*ccd->baseClasses()); + for ( ; bcli.current() ; ++bcli) { - BaseClassListIterator bcli(*ccd->baseClasses()); - for ( ; bcli.current() ; ++bcli) + if (getLink(yyscanner,bcli.current()->classDef->name(),locFunc,ol,funcName)) { - if (getLink(yyscanner,bcli.current()->classDef->name(),locFunc,ol,funcName)) - { - goto exit; - } + goto exit; } } } diff --git a/src/pycode.h b/src/pycode.h index e3a01b4..8bce2a9 100644 --- a/src/pycode.h +++ b/src/pycode.h @@ -1,12 +1,10 @@ /****************************************************************************** * - * - * - * Copyright (C) 1997-2015 by Dimitri van Heesch. + * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -36,6 +34,8 @@ class Definition; class PythonCodeParser : public CodeParserInterface { public: + PythonCodeParser(); + virtual ~PythonCodeParser(); void parseCode(CodeOutputInterface &codeOutIntf, const char *scopeName, const QCString &input, @@ -52,6 +52,9 @@ class PythonCodeParser : public CodeParserInterface bool collectXrefs=TRUE ); void resetCodeParserState(); + private: + struct Private; + std::unique_ptr p; }; diff --git a/src/pycode.l b/src/pycode.l index 8cb85a3..68ec265 100644 --- a/src/pycode.l +++ b/src/pycode.l @@ -1,12 +1,10 @@ /****************************************************************************** * - * - * - * Copyright (C) 1997-2015 by Dimitri van Heesch. + * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -23,6 +21,8 @@ %option never-interactive %option prefix="pycodeYY" +%option reentrant +%option extra-type="struct pycodeYY_state *" %option noyy_top_state %top{ #include @@ -30,12 +30,15 @@ %{ +#include +#include +#include +#include + #include -#include #include "pycode.h" #include "message.h" - #include "scanner.h" #include "entry.h" #include "doxygen.h" @@ -59,279 +62,1002 @@ #define USE_STATE2STRING 0 -static ClassSDict g_codeClassSDict(17); -static QCString g_curClassName; -static QStrList g_curClassBases; - - -static CodeOutputInterface * g_code; -static const char * g_inputString; //!< the code fragment as text -static int g_inputPosition; //!< read offset during parsing -static const char * g_currentFontClass; -static bool g_needsTermination; -static const Definition *g_searchCtx; -static bool g_collectXRefs; -static int g_inputLines; //!< number of line in the code fragment -static int g_yyLineNr; //!< current line number -static FileDef * g_sourceFileDef; -static Definition * g_currentDefinition; -static MemberDef * g_currentMemberDef; -static bool g_includeCodeFragment; -static QCString g_realScope; -//static bool g_insideBody; -static int g_bodyCurlyCount; -static bool g_searchingForBody; -static QCString g_classScope; -static int g_paramParens; -//static int g_anchorCount; - -static bool g_exampleBlock; -static QCString g_exampleName; - -static QCString g_type; -static QCString g_name; - -static bool g_doubleStringIsDoc; -static bool g_doubleQuote; -static bool g_noSuiteFound; -static int g_stringContext; - -static QValueStack g_indents; //!< Tracks indentation levels for scoping in python - -static QCString g_docBlock; //!< contents of all lines of a documentation block -static bool g_endComment; - -static void endFontClass(); -static void adjustScopesAndSuites(unsigned indentLength); - -#if USE_STATE2STRING -static const char *stateToString(int state); -#endif - - /*! Represents a stack of variable to class mappings as found in the * code. Each scope is enclosed in pushScope() and popScope() calls. * Variables are added by calling addVariables() and one can search * for variable using findVariable(). */ -class PyVariableContext +class PyVariableContext { public: - static const ClassDef *dummyContext; - class Scope : public SDict - { - public: - Scope() : SDict(17) {} - }; - - PyVariableContext() - { - m_scopes.setAutoDelete(TRUE); - } + static const ClassDef *dummyContext; - virtual ~PyVariableContext() - { - } - - void pushScope() + using Scope = std::unordered_map; + + void pushScope() { - m_scopes.append(new Scope); + m_scopes.push_back(Scope()); } - void popScope() + void popScope() { - if (m_scopes.count()>0) + if (!m_scopes.empty()) { - m_scopes.remove(m_scopes.count()-1); + m_scopes.pop_back(); } } - void clear() + void clear() { m_scopes.clear(); m_globalScope.clear(); } - void clearExceptGlobal() + void clearExceptGlobal() { m_scopes.clear(); } - void addVariable(const QCString &type,const QCString &name); - ClassDef *findVariable(const QCString &name); - + void addVariable(yyscan_t yyscanner, const QCString &type,const QCString &name); + const ClassDef *findVariable(const QCString &name); + + private: + Scope m_globalScope; + std::vector m_scopes; +}; + +class PyCallContext +{ + public: + struct Ctx + { + Ctx(QCString name_,QCString type_) : name(name_), type(type_) {} + QCString name; + QCString type; + const ClassDef *cd = 0; + }; + + PyCallContext() + { + clear(); + } + + void setClass(const ClassDef *cd) + { + Ctx &ctx = m_classList.back(); + ctx.cd=cd; + } + void pushScope(const QCString &name_,const QCString type_) + { + m_classList.push_back(Ctx(name_,type_)); + } + void popScope(QCString &name_,QCString &type_) + { + if (m_classList.size()>1) + { + const Ctx &ctx = m_classList.back(); + name_ = ctx.name; + type_ = ctx.type; + m_classList.pop_back(); + } + } + void clear() + { + m_classList.clear(); + m_classList.push_back(Ctx("","")); + } + const ClassDef *getClass() const + { + return m_classList.back().cd; + } + private: - Scope m_globalScope; - QList m_scopes; + std::vector m_classList; }; -void PyVariableContext::addVariable(const QCString &type,const QCString &name) + +struct pycodeYY_state +{ + std::unordered_map< std::string, std::unique_ptr > codeClassMap; + QCString curClassName; + QStrList curClassBases; + + CodeOutputInterface * code = 0; + const char * inputString = 0; //!< the code fragment as text + int inputPosition = 0; //!< read offset during parsing + const char * currentFontClass = 0; + bool needsTermination = FALSE; + const Definition *searchCtx = 0; + bool collectXRefs = FALSE; + int inputLines = 0; //!< number of line in the code fragment + int yyLineNr = 0; //!< current line number + FileDef * sourceFileDef = 0; + Definition * currentDefinition = 0; + MemberDef * currentMemberDef = 0; + bool includeCodeFragment = FALSE; + QCString realScope; + int bodyCurlyCount = 0; + bool searchingForBody = FALSE; + QCString classScope; + int paramParens = 0; + + bool exampleBlock = FALSE; + QCString exampleName; + + QCString type; + QCString name; + + bool doubleStringIsDoc = FALSE; + bool doubleQuote = FALSE; + bool noSuiteFound = FALSE; + int stringContext = 0; + + std::stack indents; //!< Tracks indentation levels for scoping in python + + QCString docBlock; //!< contents of all lines of a documentation block + bool endComment = FALSE; + PyVariableContext theVarContext; + PyCallContext theCallContext; +}; + + +#if USE_STATE2STRING +static const char *stateToString(int state); +#endif + +const ClassDef *PyVariableContext::dummyContext = (ClassDef*)0x8; + + +static void startCodeLine(yyscan_t yyscanner); +static int countLines(yyscan_t yyscanner); +static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor); +static void addToSearchIndex(yyscan_t yyscanner, const char *text); +static const ClassDef *stripClassName(yyscan_t yyscanner,const char *s,Definition *d); +static void codify(yyscan_t yyscanner,const char* text); +static void endCodeLine(yyscan_t yyscanner); +static void nextCodeLine(yyscan_t yyscanner); +static void writeMultiLineCodeLink(yyscan_t yyscanner, CodeOutputInterface &ol, const Definition *d, const char *text); +static void startFontClass(yyscan_t yyscanner,const char *s); +static void endFontClass(yyscan_t yyscanner); +static void codifyLines(yyscan_t yyscanner,const char *text); +static bool getLinkInScope(yyscan_t yyscanner, const QCString &c, const QCString &m, + const char *memberText, CodeOutputInterface &ol, const char *text); +static bool getLink(yyscan_t yyscanner, const char *className, const char *memberName, + CodeOutputInterface &ol, const char *text=0); +static void generateClassOrGlobalLink(yyscan_t yyscanner, CodeOutputInterface &ol, + const char *clName, bool typeOnly=FALSE); +static void generateFunctionLink(yyscan_t yyscanner, CodeOutputInterface &ol, + const char *funcName); +static bool findMemberLink(yyscan_t yyscanner, CodeOutputInterface &ol, + Definition *sym, const char *symName); +static void findMemberLink(yyscan_t yyscanner, CodeOutputInterface &ol, + const char *symName); +static void adjustScopesAndSuites(yyscan_t yyscanner,unsigned indentLength); +static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size); + + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size); + +%} + + +BB [ \t]+ +B [ \t]* +NEWLINE \n + +DIGIT [0-9] +LETTER [A-Za-z\x80-\xFF] +NONEMPTY [A-Za-z0-9_\x80-\xFF] +EXPCHAR [#(){}\[\],:.%/\\=`*~|&<>!;+-] +NONEMPTYEXP [^ \t\n:] +PARAMNONEMPTY [^ \t\n():] +IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")* +BORDER ([^A-Za-z0-9]) + +POUNDCOMMENT "##" + +TRISINGLEQUOTE "'''" +TRIDOUBLEQUOTE "\"\"\"" +LONGSTRINGCHAR [^\\"'] +ESCAPESEQ ("\\")(.) +LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ}) +SMALLQUOTE ("\"\""|"\""|"'"|"''") +LONGSTRINGBLOCK ({LONGSTRINGITEM}+|{SMALLQUOTE}) + +SHORTSTRING ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"') +SHORTSTRINGITEM ({SHORTSTRINGCHAR}|{ESCAPESEQ}) +SHORTSTRINGCHAR [^\\\n"] +STRINGLITERAL {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING}) +STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR") +KEYWORD ("lambda"|"import"|"class"|"assert"|"with"|"as"|"from"|"global"|"def"|"True"|"False") +FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally") +QUOTES ("\""[^"]*"\"") +SINGLEQUOTES ("'"[^']*"'") + +LONGINTEGER {INTEGER}("l"|"L") +INTEGER ({DECIMALINTEGER}|{OCTINTEGER}|{HEXINTEGER}) +DECIMALINTEGER ({NONZERODIGIT}{DIGIT}*|"0") +OCTINTEGER "0"{OCTDIGIT}+ +HEXINTEGER "0"("x"|"X"){HEXDIGIT}+ +NONZERODIGIT [1-9] +OCTDIGIT [0-7] +HEXDIGIT ({DIGIT}|[a-f]|[A-F]) +FLOATNUMBER ({POINTFLOAT}|{EXPONENTFLOAT}) +POINTFLOAT ({INTPART}?{FRACTION}|{INTPART}".") +EXPONENTFLOAT ({INTPART}|{POINTFLOAT}){EXPONENT} +INTPART {DIGIT}+ +FRACTION "."{DIGIT}+ +EXPONENT ("e"|"E")("+"|"-")?{DIGIT}+ +IMAGNUMBER ({FLOATNUMBER}|{INTPART})("j"|"J") +ATOM ({IDENTIFIER}|{LITERAL}|{ENCLOSURE}) +ENCLOSURE ({PARENTH_FORM}|{LIST_DISPLAY}|{DICT_DISPLAY}|{STRING_CONVERSION}) +LITERAL ({STRINGLITERAL}|{INTEGER}|{LONGINTEGER}|{FLOATNUMBER}|{IMAGNUMBER}) +PARENTH_FORM "("{EXPRESSION_LIST}?")" +TEST ({AND_TEST}("or"{AND_TEST})*|{LAMBDA_FORM}) +TESTLIST {TEST}( ","{TEST})*","? +LIST_DISPLAY "["{LISTMAKER}?"]" +LISTMAKER {EXPRESSION}({LIST_FOR}|(","{EXPRESSION})*","?) +LIST_ITER ({LIST_FOR}|{LIST_IF}) +LIST_FOR "for"{EXPRESSION_LIST}"in"{TESTLIST}{LIST_ITER}? +LIST_IF "if"{TEST}{LIST_ITER}? +DICT_DISPLAY "\{"{KEY_DATUM_LIST}?"\}" +KEY_DATUM_LIST {KEY_DATUM}(","{KEY_DATUM})*","? +KEY_DATUM {EXPRESSION}":"{EXPRESSION} +STRING_CONVERSION "`"{EXPRESSION_LIST}"`" +PRIMARY ({ATOM}|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}|{CALL}) +ATTRIBUTEREF {PRIMARY}"."{IDENTIFIER} +SUBSCRIPTION {PRIMARY}"["{EXPRESSION_LIST}"]" +SLICING ({SIMPLE_SLICING}|{EXTENDED_SLICING}) +SIMPLE_SLICING {PRIMARY}"["{SHORT_SLICE}"]" +EXTENDED_SLICING {PRIMARY}"["{SLICE_LIST}"]" +SLICE_LIST {SLICE_ITEM}(","{SLICE_ITEM})*","? +SLICE_ITEM ({EXPRESSION}|{PROPER_SLICE}|{ELLIPSIS}) +PROPER_SLICE ({SHORT_SLICE}|{LONG_SLICE}) +SHORT_SLICE {LOWER_BOUND}?":"{UPPER_BOUND}? +LONG_SLICE {SHORT_SLICE}":"{STRIDE}? +LOWER_BOUND {EXPRESSION} +UPPER_BOUND {EXPRESSION} +STRIDE {EXPRESSION} +ELLIPSIS "..." +CALL {PRIMARY}"("({ARGUMENT_LIST}","?)?")" +ARGUMENT_LIST ({POSITIONAL_ARGUMENTS}(","{KEYWORD_ARGUMENTS})?(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|{KEYWORD_ARGUMENTS}(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|"*"{EXPRESSION}(",""**"{EXPRESSION})?|"**"{EXPRESSION}) +POSITIONAL_ARGUMENTS {EXPRESSION}(","{EXPRESSION})* +KEYWORD_ARGUMENTS {KEYWORD_ITEM}(","{KEYWORD_ITEM})* +KEYWORD_ITEM {IDENTIFIER}"="{EXPRESSION} +POWER {PRIMARY}("**"{U_EXPR})? +U_EXPR ({POWER}|"-"{U_EXPR}|"+"{U_EXPR}|"\~"{U_EXPR}) +M_EXPR ({U_EXPR}|{M_EXPR}"*"{U_EXPR}|{M_EXPR}"//"{U_EXPR}|{M_EXPR}"/"{U_EXPR}|{M_EXPR}"\%"{U_EXPR}) +A_EXPR ({M_EXPR}|{A_EXPR}"+"{M_EXPR}|{A_EXPR}"-"{M_EXPR} +SHIFT_EXPR ({A_EXPR}|{SHIFT_EXPR}("<<"|">>"){A_EXPR}) +AND_EXPR ({SHIFT_EXPR}|{AND_EXPR}"\;SPMamp;"{SHIFT_EXPR} +XOR_EXPR ({AND_EXPR}|{XOR_EXPR}"\textasciicircum"{AND_EXPR}) +OR_EXPR ({XOR_EXPR}|{OR_EXPR}"|"{ XOR_EXPR}) + +COMPARISON {OR_EXPR}({COMP_OPERATOR}{OR_EXPR})* +COMP_OPERATOR ("<"|">"|"=="|">="|"<="|"<>"|"!="|"is""not"?|"not"?"in") +EXPRESSION ({OR_TEST}|{LAMBDA_FORM}) +OR_TEST ({AND_TEST}|{OR_TEST}"or"{AND_TEST}) +AND_TEST ({NOT_TEST}|{AND_TEST}"and"{NOT_TEST}) +NOT_TEST ({COMPARISON}|"not"{NOT_TEST}) +LAMBDA_FORM "lambda"{PARAMETER_LIST}?":"{EXPRESSION} +EXPRESSION_LIST {EXPRESSION}(","{EXPRESSION})*","? +SIMPLE_STMT ({EXPRESSION_STMT}|{ASSERT_STMT}|{ASSIGNMENT_STMT}|{AUGMENTED_ASSIGNMENT_STMT}|{PASS_STMT}|{DEL_STMT}|{PRINT_STMT}|{RETURN_STMT}|{YIELD_STMT}|{RAISE_STMT}|{BREAK_STMT}|{CONTINUE_STMT}|{IMPORT_STMT}|{GLOBAL_STMT}|{EXEC_STMT}) +EXPRESSION_STMT {EXPRESSION_LIST} +ASSERT_STMT "assert"{EXPRESSION}(","{EXPRESSION})? +ASSIGNMENT_STMT ({TARGET_LIST}"=")+{EXPRESSION_LIST} +TARGET_LIST {TARGET}(","{TARGET})*","? +TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}) + +%option noyywrap +%option stack + +%x Body + +%x FunctionDec +%x FunctionParams + +%x ClassDec +%x ClassInheritance + +%x Suite +%x SuiteCaptureIndent +%x SuiteStart +%x SuiteMaintain +%x SuiteContinuing + +%x LongString + +%x SingleQuoteString +%x DoubleQuoteString +%x TripleString + +%x DocBlock +%% + +{ + "def"{BB} { + startFontClass(yyscanner,"keyword"); + codify(yyscanner,yytext); + endFontClass(yyscanner); + BEGIN( FunctionDec ); + } + + "class"{BB} { + startFontClass(yyscanner,"keyword"); + codify(yyscanner,yytext); + endFontClass(yyscanner); + BEGIN( ClassDec ); + } + "None" { + startFontClass(yyscanner,"keywordtype"); + codify(yyscanner,yytext); + endFontClass(yyscanner); + } + "self."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER}"(" { + codify(yyscanner,"self."); + findMemberLink(yyscanner,*yyextra->code,&yytext[5]); + } + "self."{IDENTIFIER}/"(" { + codify(yyscanner,"self."); + findMemberLink(yyscanner,*yyextra->code,&yytext[5]); + } + "self."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER} { + codify(yyscanner,"self."); + findMemberLink(yyscanner,*yyextra->code,&yytext[5]); + } + "self."{IDENTIFIER} { + codify(yyscanner,"self."); + findMemberLink(yyscanner,*yyextra->code,&yytext[5]); + } + "cls."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER}"(" { + codify(yyscanner,"cls."); + findMemberLink(yyscanner,*yyextra->code,&yytext[4]); + } + "cls."{IDENTIFIER}/"(" { + codify(yyscanner,"cls."); + findMemberLink(yyscanner,*yyextra->code,&yytext[4]); + } + "cls."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER} { + codify(yyscanner,"cls."); + findMemberLink(yyscanner,*yyextra->code,&yytext[4]); + } + "cls."{IDENTIFIER} { + codify(yyscanner,"cls."); + findMemberLink(yyscanner,*yyextra->code,&yytext[4]); + } +} + +{IDENTIFIER} { + generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext); + // codify(yyscanner,yytext); + yyextra->curClassName = yytext; + yyextra->curClassBases.clear(); + BEGIN( ClassInheritance ); + } + +{ + ({BB}|[(,)]) { + codify(yyscanner,yytext); + } + + ({IDENTIFIER}".")*{IDENTIFIER} { + // The parser + // is assuming + // that ALL identifiers + // in this state + // are base classes; + // it doesn't check to see + // that the first parenthesis + // has been seen. + + // This is bad - it should + // probably be more strict + // about what to accept. + + yyextra->curClassBases.inSort(yytext); + generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext); + // codify(yyscanner,yytext); + } + + ":" { + codify(yyscanner,yytext); + + // Assume this will + // be a one-line suite; + // found counter-example + // in SuiteStart. + + // Push a class scope + + std::unique_ptr classDefToAdd { createClassDef("",1,1,yyextra->curClassName,ClassDef::Class,0,0,FALSE) }; + char *s=yyextra->curClassBases.first(); + while (s) + { + const ClassDef *baseDefToAdd = 0; + // find class in the local scope + auto it = yyextra->codeClassMap.find(s); + if (it != yyextra->codeClassMap.end()) + { + baseDefToAdd = it->second.get(); + } + // Try to find class in global scope + if (baseDefToAdd==0) + { + baseDefToAdd=getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,s); + } + + if (baseDefToAdd && baseDefToAdd!=classDefToAdd.get()) + { + classDefToAdd->insertBaseClass(const_cast(baseDefToAdd),s,Public,Normal); + } + + s=yyextra->curClassBases.next(); + } + yyextra->codeClassMap.emplace(std::make_pair(yyextra->curClassName.str(),std::move(classDefToAdd))); + + // Reset class-parsing variables. + yyextra->curClassName.resize(0); + yyextra->curClassBases.clear(); + + yyextra->noSuiteFound = TRUE; + BEGIN( SuiteStart ); + } +} + + +{ + {IDENTIFIER} { + generateFunctionLink(yyscanner,*yyextra->code,yytext); + } + + {B}"(" { + codify(yyscanner,yytext); + BEGIN( FunctionParams ); + } +} + +{ + ({BB}|",") { + // Parses delimiters + codify(yyscanner,yytext); + } + + ({IDENTIFIER}|{PARAMNONEMPTY}+) { + codify(yyscanner,yytext); + } + + ")" { + codify(yyscanner,yytext); + } + + "\n" { + codifyLines(yyscanner,yytext); + } + + ":" { + codify(yyscanner,yytext); + + // Assume this will + // be a one-line suite; + // found counter-example + // in SuiteStart. + yyextra->noSuiteFound = TRUE; + BEGIN( SuiteStart ); + } +} + +{ + + {KEYWORD} { + // Position-sensitive rules! + // Must come AFTER keyword-triggered rules + // Must come BEFORE identifier NONEMPTY-like rules + // to syntax highlight. + + startFontClass(yyscanner,"keyword"); + codify(yyscanner,yytext); + endFontClass(yyscanner); + } + + {FLOWKW} { + if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction()) + { + yyextra->currentMemberDef->incrementFlowKeyWordCount(); + } + startFontClass(yyscanner,"keywordflow"); + codify(yyscanner,yytext); + endFontClass(yyscanner); + } + ({IDENTIFIER}".")*{IDENTIFIER}/"(" { + generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext); + } + ({IDENTIFIER}".")+{IDENTIFIER} { + generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,TRUE); + } + {IDENTIFIER} { codify(yyscanner,yytext); } + +} + + + +{ + + {BB} { + codify(yyscanner,yytext); + } + "pass" { + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + BEGIN(Body); + } + {KEYWORD} { + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + + // No indentation necessary + yyextra->noSuiteFound = FALSE; + } + + {FLOWKW} { + if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction()) + { + yyextra->currentMemberDef->incrementFlowKeyWordCount(); + } + startFontClass(yyscanner,"keywordflow"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + + // No indentation necessary + yyextra->noSuiteFound = FALSE; + } + {IDENTIFIER} { + codify(yyscanner,yytext); + } + + + {POUNDCOMMENT} { + if (YY_START==SingleQuoteString || + YY_START==DoubleQuoteString || + YY_START==TripleString + ) + { + REJECT; + } + yy_push_state(YY_START,yyscanner); + BEGIN(DocBlock); + yyextra->docBlock=yytext; + } + + {NEWLINE} { + codifyLines(yyscanner,yytext); + if ( yyextra->noSuiteFound ) + { + // printf("New suite to capture! [%d]\n", yyextra->yyLineNr); + BEGIN ( SuiteCaptureIndent ); + } + } +} + +{ + "\n"|({BB}"\n") { + // Blankline - ignore, keep looking for indentation. + codifyLines(yyscanner,yytext); + } + + {BB} { + // This state lasts momentarily, + // to check the indentation + // level that is about to be + // used. + codifyLines(yyscanner,yytext); + yyextra->indents.push(yyleng); + // printf("Captured indent of %d [line %d]\n", yyleng, yyextra->yyLineNr); + BEGIN( Suite ); + } +} + +{ + + {BB}/({NONEMPTY}|{EXPCHAR}) { + // This implements poor + // indentation-tracking; + // should be improved. + // (translate tabs to space, etc) + codifyLines(yyscanner,yytext); + adjustScopesAndSuites(yyscanner,static_cast(yyleng)); + } + + "\n"|({BB}"\n") { + // If this ever succeeds, + // it means that this is + // a blank line, and + // can be ignored. + codifyLines(yyscanner,yytext); + } + + ""/({NONEMPTY}|{EXPCHAR}) { + // Default rule; matches + // the empty string, assuming + // real text starts here. + // Just go straight to Body. + adjustScopesAndSuites(yyscanner,0); + } +} + + +{NEWLINE} { + codifyLines(yyscanner,yytext); + BEGIN( SuiteMaintain ); + } +{IDENTIFIER} { + codify(yyscanner,yytext); + } +{NEWLINE} { + codifyLines(yyscanner,yytext); + } + +{ // Single quoted string like 'That\'s a """nice""" string!' + \\{B}\n { // line continuation + codifyLines(yyscanner,yytext); + } + \\. { // escaped char + codify(yyscanner,yytext); + } + {STRINGPREFIX}?{TRIDOUBLEQUOTE} { // triple double quotes + codify(yyscanner,yytext); + } + "'" { // end of the string + codify(yyscanner,yytext); + endFontClass(yyscanner); + BEGIN(yyextra->stringContext); + } + [^"'\n\\]+ { // normal chars + codify(yyscanner,yytext); + } + . { // normal char + codify(yyscanner,yytext); + } +} + +{ // Double quoted string like "That's \"a '''nice'''\" string!" + \\{B}\n { // line continuation + codifyLines(yyscanner,yytext); + } + \\. { // escaped char + codify(yyscanner,yytext); + } + {STRINGPREFIX}?{TRISINGLEQUOTE} { // triple single quotes + codify(yyscanner,yytext); + } + "\"" { // end of the string + codify(yyscanner,yytext); + endFontClass(yyscanner); + BEGIN(yyextra->stringContext); + } + [^"'\n\\]+ { // normal chars + codify(yyscanner,yytext); + } + . { // normal char + codify(yyscanner,yytext); + } +} + +{ + {TRIDOUBLEQUOTE} | + {TRISINGLEQUOTE} { + codify(yyscanner,yytext); + if (yyextra->doubleQuote==(yytext[0]=='"')) + { + endFontClass(yyscanner); + BEGIN(yyextra->stringContext); + } + } + {LONGSTRINGBLOCK} { + codifyLines(yyscanner,yytext); + } + \n { + codifyLines(yyscanner,yytext); + } + . { + codify(yyscanner,yytext); + } +} + + +<*>{STRINGPREFIX}?{TRISINGLEQUOTE} { + if (YY_START==SingleQuoteString) REJECT; + startFontClass(yyscanner,"stringliteral"); + yyextra->stringContext=YY_START; + yyextra->doubleQuote=yytext[yyleng-1]=='"'; + codify(yyscanner,yytext); + BEGIN(TripleString); + } +<*>{STRINGPREFIX}?{TRIDOUBLEQUOTE} { + if (YY_START==DoubleQuoteString) REJECT; + startFontClass(yyscanner,"stringliteral"); + yyextra->stringContext=YY_START; + yyextra->doubleQuote=yytext[yyleng-1]=='"'; + codify(yyscanner,yytext); + BEGIN(TripleString); + } +<*>{STRINGPREFIX}?"'" { // single quoted string + if (YY_START==SingleQuoteString || + YY_START==DoubleQuoteString || + YY_START==TripleString) + { + REJECT; + } + startFontClass(yyscanner,"stringliteral"); + yyextra->stringContext=YY_START; + codify(yyscanner,yytext); + BEGIN(SingleQuoteString); + } +<*>{STRINGPREFIX}?"\"" { // double quoted string + if (YY_START==SingleQuoteString || + YY_START==DoubleQuoteString || + YY_START==TripleString) + { + REJECT; + } + startFontClass(yyscanner,"stringliteral"); + yyextra->stringContext=YY_START; + codify(yyscanner,yytext); + BEGIN(DoubleQuoteString); + } +.* { // contents of current comment line + yyextra->docBlock+=yytext; + } +"\n"{B}("#") { // comment block (next line is also comment line) + yyextra->docBlock+=yytext; + } +{NEWLINE} { // comment block ends at the end of this line + // remove special comment (default config) + if (Config_getBool(STRIP_CODE_COMMENTS)) + { + yyextra->yyLineNr+=((QCString)yyextra->docBlock).contains('\n'); + yyextra->endComment=TRUE; + } + else // do not remove comment + { + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yyextra->docBlock); + endFontClass(yyscanner); + } + unput(*yytext); + yy_pop_state(yyscanner); + } +<*>{POUNDCOMMENT}.* { + if (YY_START==SingleQuoteString || + YY_START==DoubleQuoteString || + YY_START==TripleString) + { + REJECT; + } + yy_push_state(YY_START,yyscanner); + BEGIN(DocBlock); + yyextra->docBlock=yytext; + } +<*>"#".* { // normal comment + if (YY_START==SingleQuoteString || + YY_START==DoubleQuoteString || + YY_START==TripleString) + { + REJECT; + } + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<*>{NEWLINE} { + if (yyextra->endComment) + { + yyextra->endComment=FALSE; + } + else + { + codifyLines(yyscanner,yytext); + } + //printf("[pycode] %d NEWLINE [line %d] no match\n", + // YY_START, yyextra->yyLineNr); + + BEGIN(Body); + } + +<*>[ \t]+ { + codify(yyscanner,yytext); + BEGIN(Body); + } +<*>. { + codify(yyscanner,yytext); + // printf("[pycode] '%s' [ state %d ] [line %d] no match\n", + // yytext, YY_START, yyextra->yyLineNr); + + BEGIN(Body); + } + +<*><> { + if (YY_START==DocBlock && !Config_getBool(STRIP_CODE_COMMENTS)) + { + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yyextra->docBlock); + endFontClass(yyscanner); + } + yyterminate(); + } +%% + +/*@ ---------------------------------------------------------------------------- + */ + +void PyVariableContext::addVariable(yyscan_t yyscanner, const QCString &type,const QCString &name) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; //printf("PyVariableContext::addVariable(%s,%s)\n",type.data(),name.data()); QCString ltype = type.simplifyWhiteSpace(); QCString lname = name.simplifyWhiteSpace(); - Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast(); - const ClassDef *varType; - if ( - (varType=g_codeClassSDict[ltype]) || // look for class definitions inside the code block - (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions - ) + Scope *scope = m_scopes.empty() ? &m_globalScope : &m_scopes.back(); + const ClassDef *varType = 0; + auto it = yyextra->codeClassMap.find(ltype.str()); + if (it!=yyextra->codeClassMap.end()) { - scope->append(lname,varType); // add it to a list + varType = it->second.get(); } - else + if (varType==0) { - if (m_scopes.count()>0) // for local variables add a dummy entry so the name - // is hidden to avoid FALSE links to global variables with the same name - // TODO: make this work for namespaces as well! + varType = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,ltype); // look for global class definitions + } + if (varType) + { + scope->emplace(std::make_pair(lname.str(),varType)); // add it to a list + } + else + { + if (!m_scopes.empty()) // for local variable add a dummy entry to avoid linking to a global that is + // shadowed. { - scope->append(lname,dummyContext); + scope->emplace(std::make_pair(lname.str(),dummyContext)); } } } -ClassDef *PyVariableContext::findVariable(const QCString &name) +const ClassDef *PyVariableContext::findVariable(const QCString &name) { if (name.isEmpty()) return 0; - ClassDef *result = 0; - QListIterator sli(m_scopes); - Scope *scope; + const ClassDef *result = 0; + // search from inner to outer scope - for (sli.toLast();(scope=sli.current());--sli) + auto it = std::rbegin(m_scopes); + while (it != std::rend(m_scopes)) { - result = scope->find(name); - if (result) + auto it2 = it->find(name.str()); + if (it2 != std::end(*it)) { + result = it2->second; return result; } + ++it; } // nothing found -> also try the global scope - result=m_globalScope.find(name); + auto it2 = m_globalScope.find(name.str()); + if (it2 != m_globalScope.end()) + { + result = it2->second; + } return result; } -static PyVariableContext g_theVarContext; -const ClassDef *PyVariableContext::dummyContext = (ClassDef*)0x8; +//------------------------------------------------------------------------------- -class PyCallContext +static yy_size_t yyread(yyscan_t yyscanner, char *buf,yy_size_t max_size) { - public: - struct Ctx - { - Ctx() : name(g_name), type(g_type), cd(0) {} - QCString name; - QCString type; - const ClassDef *cd; - }; - - PyCallContext() - { - m_classList.append(new Ctx); - m_classList.setAutoDelete(TRUE); - } - - virtual ~PyCallContext() {} - - void setClass(const ClassDef *cd) - { - Ctx *ctx = m_classList.getLast(); - if (ctx) - { - ctx->cd=cd; - } - } - void pushScope() - { - m_classList.append(new Ctx); - } + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + yy_size_t inputPosition = yyextra->inputPosition; + const char *s = yyextra->inputString + inputPosition; + yy_size_t c=0; + while( c < max_size && *s ) + { + *buf++ = *s++; + c++; + } + yyextra->inputPosition += c; + return c; +} - void popScope() - { - if (m_classList.count()>1) - { - Ctx *ctx = m_classList.getLast(); - if (ctx) - { - g_name = ctx->name; - g_type = ctx->type; - } - m_classList.removeLast(); - } - else - { - } - } +//------------------------------------------------------------------------------- - void clear() - { - m_classList.clear(); - m_classList.append(new Ctx); - } - - const ClassDef *getClass() const +/*! + Examines current stack of white-space indentations; + re-syncs the parser with the correct scope. +*/ +static void adjustScopesAndSuites(yyscan_t yyscanner,unsigned indentLength) +{ + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + // States to pop + if (!yyextra->indents.empty() && indentLength < yyextra->indents.top()) + { + while (!yyextra->indents.empty() && indentLength < yyextra->indents.top()) { - Ctx *ctx = m_classList.getLast(); + // printf("Exited scope indent of [%d]\n", yyextra->indents.top()); + yyextra->indents.pop(); // Pop the old suite's indentation - if (ctx) - return ctx->cd; - else - return 0; + yyextra->currentMemberDef=0; + if (yyextra->currentDefinition) + yyextra->currentDefinition=yyextra->currentDefinition->getOuterScope(); } + } - private: - QList m_classList; -}; - -static PyCallContext g_theCallContext; + // Are there any remaining indentation levels for suites? + if (!yyextra->indents.empty()) + { + BEGIN( Suite ); + } + else + { + BEGIN( Body ); + } +} +//------------------------------------------------------------------------------- /*! counts the number of lines in the input */ -static int countLines() +static int countLines(yyscan_t yyscanner) { - const char *p=g_inputString; + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + const char *p=yyextra->inputString; char c; int count=1; - while ((c=*p)) - { - p++ ; - if (c=='\n') count++; + while ((c=*p)) + { + p++; + if (c=='\n') count++; } - if (p>g_inputString && *(p-1)!='\n') + if (p>yyextra->inputString && *(p-1)!='\n') { // last line does not end with a \n, so we add an extra // line and explicitly terminate the line after parsing. - count++, - g_needsTermination=TRUE; - } + count++; + yyextra->needsTermination=TRUE; + } return count; } -static void setCurrentDoc(const QCString &anchor) +//------------------------------------------------------------------------------- + +static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (Doxygen::searchIndex) { - if (g_searchCtx) + if (yyextra->searchCtx) { - Doxygen::searchIndex->setCurrentDoc(g_searchCtx,g_searchCtx->anchor(),FALSE); + yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE); } else { - Doxygen::searchIndex->setCurrentDoc(g_sourceFileDef,anchor,TRUE); + yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,TRUE); } } } -static void addToSearchIndex(const char *text) +//------------------------------------------------------------------------------- + +static void addToSearchIndex(yyscan_t yyscanner, const char *text) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (Doxygen::searchIndex) { - Doxygen::searchIndex->addWord(text,FALSE); + yyextra->code->addWord(text,FALSE); } } +//------------------------------------------------------------------------------- -static const ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition) +static const ClassDef *stripClassName(yyscan_t yyscanner,const char *s,Definition *d) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; int pos=0; QCString type = s; QCString className; @@ -339,15 +1065,14 @@ static const ClassDef *stripClassName(const char *s,Definition *d=g_currentDefin while (extractClassNameFromType(type,pos,className,templSpec)!=-1) { QCString clName=className+templSpec; - const ClassDef *cd=0; - if (!g_classScope.isEmpty()) + if (!yyextra->classScope.isEmpty()) { - cd=getResolvedClass(d,g_sourceFileDef,g_classScope+"::"+clName); + cd=getResolvedClass(d,yyextra->sourceFileDef,yyextra->classScope+"::"+clName); } if (cd==0) { - cd=getResolvedClass(d,g_sourceFileDef,clName); + cd=getResolvedClass(d,yyextra->sourceFileDef,clName); } if (cd) { @@ -358,104 +1083,117 @@ static const ClassDef *stripClassName(const char *s,Definition *d=g_currentDefin return 0; } +//------------------------------------------------------------------------------- - -/*! start a new line of code, inserting a line number if g_sourceFileDef +/*! start a new line of code, inserting a line number if yyextra->sourceFileDef * is TRUE. If a definition starts at the current line, then the line * number is linked to the documentation of that definition. */ -static void startCodeLine() +static void startCodeLine(yyscan_t yyscanner) { - //if (g_currentFontClass) { g_code->endFontClass(); } - if (g_sourceFileDef) + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + //if (yyextra->currentFontClass) { yyextra->code->endFontClass(yyscanner); } + if (yyextra->sourceFileDef) { //QCString lineNumber,lineAnchor; - //lineNumber.sprintf("%05d",g_yyLineNr); - //lineAnchor.sprintf("l%05d",g_yyLineNr); - - Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr); - //printf("startCodeLine %d d=%p\n",g_yyLineNr,d); - //g_code->startLineNumber(); - - if (!g_includeCodeFragment && d && d->isLinkableInProject()) + //lineNumber.sprintf("%05d",yyextra->yyLineNr); + //lineAnchor.sprintf("l%05d",yyextra->yyLineNr); + + Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr); + //printf("startCodeLine %d d=%p\n",yyextra->yyLineNr,d); + //yyextra->code->startLineNumber(); + + if (!yyextra->includeCodeFragment && d && d->isLinkableInProject()) { - g_currentDefinition = d; - g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr); - //g_insideBody = FALSE; - g_endComment = FALSE; - g_searchingForBody = TRUE; - g_realScope = d->name().copy(); - g_classScope = d->name().copy(); - //printf("Real scope: '%s'\n",g_realScope.data()); - g_bodyCurlyCount = 0; + yyextra->currentDefinition = d; + yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr); + //yyextra->insideBody = FALSE; + yyextra->endComment = FALSE; + yyextra->searchingForBody = TRUE; + yyextra->realScope = d->name().copy(); + yyextra->classScope = d->name().copy(); + //printf("Real scope: '%s'\n",yyextra->realScope.data()); + yyextra->bodyCurlyCount = 0; QCString lineAnchor; - lineAnchor.sprintf("l%05d",g_yyLineNr); - if (g_currentMemberDef) + lineAnchor.sprintf("l%05d",yyextra->yyLineNr); + if (yyextra->currentMemberDef) { - g_code->writeLineNumber(g_currentMemberDef->getReference(), - g_currentMemberDef->getOutputFileBase(), - g_currentMemberDef->anchor(),g_yyLineNr); - setCurrentDoc(lineAnchor); + yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(), + yyextra->currentMemberDef->getOutputFileBase(), + yyextra->currentMemberDef->anchor(),yyextra->yyLineNr); + setCurrentDoc(yyscanner,lineAnchor); } else { - g_code->writeLineNumber(d->getReference(), - d->getOutputFileBase(), - 0,g_yyLineNr); - setCurrentDoc(lineAnchor); + yyextra->code->writeLineNumber(d->getReference(), + d->getOutputFileBase(), + 0,yyextra->yyLineNr); + setCurrentDoc(yyscanner,lineAnchor); } } else { - //g_code->codify(lineNumber); - g_code->writeLineNumber(0,0,0,g_yyLineNr); + //yyextra->code->codify(lineNumber); + yyextra->code->writeLineNumber(0,0,0,yyextra->yyLineNr); } - //g_code->endLineNumber(); + //yyextra->code->endLineNumber(); } - g_code->startCodeLine(g_sourceFileDef); - if (g_currentFontClass) + yyextra->code->startCodeLine(yyextra->sourceFileDef); + if (yyextra->currentFontClass) { - g_code->startFontClass(g_currentFontClass); + yyextra->code->startFontClass(yyextra->currentFontClass); } } -static void codify(const char* text) -{ - g_code->codify(text); +//------------------------------------------------------------------------------- + +static void codify(yyscan_t yyscanner,const char* text) +{ + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + yyextra->code->codify(text); } -static void endCodeLine() +//------------------------------------------------------------------------------- + +static void endCodeLine(yyscan_t yyscanner) { - endFontClass(); - g_code->endCodeLine(); + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + endFontClass(yyscanner); + yyextra->code->endCodeLine(); } -static void nextCodeLine() +//------------------------------------------------------------------------------- + +static void nextCodeLine(yyscan_t yyscanner) { - const char *fc = g_currentFontClass; - endCodeLine(); - if (g_yyLineNrcurrentFontClass; + endCodeLine(yyscanner); + if (yyextra->yyLineNrinputLines) { - g_currentFontClass = fc; - startCodeLine(); + yyextra->currentFontClass = fc; + startCodeLine(yyscanner); } } +//------------------------------------------------------------------------------- /*! writes a link to a fragment \a text that may span multiple lines, inserting - * line numbers for each line. If \a text contains newlines, the link will be + * line numbers for each line. If \a text contains newlines, the link will be * split into multiple links with the same destination, one for each line. */ -static void writeMultiLineCodeLink(CodeOutputInterface &ol, +static void writeMultiLineCodeLink(yyscan_t yyscanner, + CodeOutputInterface &ol, const Definition *d, const char *text) { - static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS); + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS); TooltipManager::instance()->addTooltip(d); QCString ref = d->getReference(); QCString file = d->getOutputFileBase(); QCString anchor = d->anchor(); - QCString tooltip; + QCString tooltip; if (!sourceTooltips) // fall back to simple "title" tooltips { tooltip = d->briefDescriptionAsTooltip(); @@ -469,11 +1207,11 @@ static void writeMultiLineCodeLink(CodeOutputInterface &ol, while ((c=*p++) && c!='\n') { } if (c=='\n') { - g_yyLineNr++; + yyextra->yyLineNr++; *(p-1)='\0'; //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp); ol.writeCodeLink(ref,file,anchor,sp,tooltip); - nextCodeLine(); + nextCodeLine(yyscanner); } else { @@ -484,141 +1222,149 @@ static void writeMultiLineCodeLink(CodeOutputInterface &ol, } } -static void startFontClass(const char *s) +//------------------------------------------------------------------------------- + +static void startFontClass(yyscan_t yyscanner,const char *s) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; // if font class is already set don't stop and start it. // strcmp does not like null pointers as input. - if (!g_currentFontClass || !s || strcmp(g_currentFontClass,s)) + if (!yyextra->currentFontClass || !s || strcmp(yyextra->currentFontClass,s)) { - endFontClass(); - g_code->startFontClass(s); - g_currentFontClass=s; + endFontClass(yyscanner); + yyextra->code->startFontClass(s); + yyextra->currentFontClass=s; } } -static void endFontClass() +//------------------------------------------------------------------------------- + +static void endFontClass(yyscan_t yyscanner) { - if (g_currentFontClass) + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + if (yyextra->currentFontClass) { - g_code->endFontClass(); - g_currentFontClass=0; + yyextra->code->endFontClass(); + yyextra->currentFontClass=0; } } -static void codifyLines(char *text) +//------------------------------------------------------------------------------- + +static void codifyLines(yyscan_t yyscanner,const char *text) { - //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text); - char *p=text,*sp=p; + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + //printf("codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,text); + const char *p=text,*sp=p; char c; bool done=FALSE; - const char * tmp_currentFontClass = g_currentFontClass; while (!done) { sp=p; while ((c=*p++) && c!='\n') { } if (c=='\n') { - g_yyLineNr++; - *(p-1)='\0'; - g_code->codify(sp); - endCodeLine(); - if (g_yyLineNryyLineNr++; + int l = (int)(p-sp-1); + char *tmp = (char*)malloc(l+1); + memcpy(tmp,sp,l); + tmp[l]='\0'; + yyextra->code->codify(tmp); + free(tmp); + nextCodeLine(yyscanner); } else { - g_code->codify(sp); + yyextra->code->codify(sp); done=TRUE; } } } -static void codifyLines(const QCString &str) -{ - char *tmp= (char *)malloc(str.length()+1); - qstrcpy(tmp, str); - codifyLines(tmp); - free(tmp); -} +//------------------------------------------------------------------------------- -static bool getLinkInScope(const QCString &c, // scope +static bool getLinkInScope(yyscan_t yyscanner, + const QCString &c, // scope const QCString &m, // member - const char *memberText, // exact text - CodeOutputInterface &ol, - const char *text - ) + const char *memberText, // exact text + CodeOutputInterface &ol, + const char *text + ) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; const MemberDef *md = 0; const ClassDef *cd = 0; const FileDef *fd = 0; const NamespaceDef *nd = 0; const GroupDef *gd = 0; //printf("Trying '%s'::'%s'\n",c.data(),m.data()); - if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef) && + if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,yyextra->sourceFileDef) && md->isLinkable()) { //Definition *d=0; //if (cd) d=cd; else if (nd) d=nd; else if (fd) d=fd; else d=gd; const Definition *d = md->getOuterScope()==Doxygen::globalScope ? - md->getBodyDef() : md->getOuterScope(); + md->getBodyDef() : md->getOuterScope(); //printf("Found! d=%s\n",d?d->name().data():""); if (md->getGroupDef()) d = md->getGroupDef(); if (d && d->isLinkable()) { - g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); - //printf("g_currentDefinition=%p g_currentMemberDef=%p\n", - // g_currentDefinition,g_currentMemberDef); + yyextra->theCallContext.setClass(stripClassName(yyscanner,md->typeString(),md->getOuterScope())); + //printf("yyextra->currentDefinition=%p yyextra->currentMemberDef=%p\n", + // yyextra->currentDefinition,yyextra->currentMemberDef); - if (g_currentDefinition && g_currentMemberDef && - md!=g_currentMemberDef && g_collectXRefs) + if (yyextra->currentDefinition && yyextra->currentMemberDef && + md!=yyextra->currentMemberDef && yyextra->collectXRefs) { - addDocCrossReference(g_currentMemberDef,const_cast(md)); + addDocCrossReference(yyextra->currentMemberDef,const_cast(md)); } //printf("d->getReference()='%s' d->getOutputBase()='%s' name='%s' member name='%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data()); - - writeMultiLineCodeLink(ol,md, text ? text : memberText); - addToSearchIndex(text ? text : memberText); + + writeMultiLineCodeLink(yyscanner,ol,md, text ? text : memberText); + addToSearchIndex(yyscanner,text ? text : memberText); return TRUE; - } + } } return FALSE; } -static bool getLink(const char *className, +//------------------------------------------------------------------------------- + +static bool getLink(yyscan_t yyscanner, + const char *className, const char *memberName, - CodeOutputInterface &ol, - const char *text=0) + CodeOutputInterface &ol, + const char *text) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; QCString m=removeRedundantWhiteSpace(memberName); QCString c=className; - if (!getLinkInScope(c,m,memberName,ol,text)) + if (!getLinkInScope(yyscanner,c,m,memberName,ol,text)) { - if (!g_curClassName.isEmpty()) + if (!yyextra->curClassName.isEmpty()) { if (!c.isEmpty()) c.prepend("::"); - c.prepend(g_curClassName); - return getLinkInScope(c,m,memberName,ol,text); + c.prepend(yyextra->curClassName); + return getLinkInScope(yyscanner,c,m,memberName,ol,text); } return FALSE; } return TRUE; } +//------------------------------------------------------------------------------- /* For a given string in the source code, finds its class or global id and links to it. */ -static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName, - bool typeOnly=FALSE) +static void generateClassOrGlobalLink(yyscan_t yyscanner, + CodeOutputInterface &ol, + const char *clName, + bool typeOnly) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; QCString className=clName; // Don't do anything for empty text @@ -630,16 +1376,16 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName, const MemberDef *md=0; /** Member def that we may find */ //bool isLocal=FALSE; - if ((lcd=g_theVarContext.findVariable(className))==0) // not a local variable + if ((lcd=yyextra->theVarContext.findVariable(className))==0) // not a local variable { - Definition *d = g_currentDefinition; + Definition *d = yyextra->currentDefinition; QCString scope = substitute(className,".","::"); - cd = getResolvedClass(d,g_sourceFileDef,substitute(className,".","::"),&md); + cd = getResolvedClass(d,yyextra->sourceFileDef,substitute(className,".","::"),&md); - DBG_CTX((stderr,"d=%s g_sourceFileDef=%s\n", + DBG_CTX((stderr,"d=%s yyextra->sourceFileDef=%s\n", d?d->displayName().data():"", - g_currentDefinition?g_currentDefinition->displayName().data():"")); + yyextra->currentDefinition?yyextra->currentDefinition->displayName().data():"")); DBG_CTX((stderr,"is found as a type %s\n",cd?cd->name().data():"")); if (cd==0 && md==0) // also see if it is variable or enum or enum value @@ -647,21 +1393,21 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName, const NamespaceDef *nd = getResolvedNamespace(scope); if (nd) { - writeMultiLineCodeLink(ol,nd,clName); - addToSearchIndex(className); + writeMultiLineCodeLink(yyscanner,ol,nd,clName); + addToSearchIndex(yyscanner,className); return; } - else if (getLink(g_classScope,clName,ol,clName)) + else if (getLink(yyscanner,yyextra->classScope,clName,ol,clName)) { - return; + return; } } } else { - if (lcd!=PyVariableContext::dummyContext) + if (lcd!=PyVariableContext::dummyContext) { - g_theCallContext.setClass(lcd); + yyextra->theCallContext.setClass(lcd); } //isLocal=TRUE; DBG_CTX((stderr,"is a local variable cd=%p!\n",cd)); @@ -669,17 +1415,17 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName, if (cd && cd->isLinkable()) // is it a linkable class { - writeMultiLineCodeLink(ol,cd,clName); - addToSearchIndex(className); + writeMultiLineCodeLink(yyscanner,ol,cd,clName); + addToSearchIndex(yyscanner,className); if (md) { const Definition *d = md->getOuterScope()==Doxygen::globalScope ? md->getBodyDef() : md->getOuterScope(); if (md->getGroupDef()) d = md->getGroupDef(); - if (d && d->isLinkable() && md->isLinkable() && - g_currentMemberDef && g_collectXRefs) + if (d && d->isLinkable() && md->isLinkable() && + yyextra->currentMemberDef && yyextra->collectXRefs) { - addDocCrossReference(g_currentMemberDef,const_cast(md)); + addDocCrossReference(yyextra->currentMemberDef,const_cast(md)); } } } @@ -694,55 +1440,57 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName, DBG_CTX((stderr,"scope=%s locName=%s mcd=%p\n",scope.data(),locName.data(),mcd)); if (mcd) { - MemberDef *mmd = mcd->getMemberByName(locName); - if (mmd) - { - g_theCallContext.setClass(stripClassName(mmd->typeString(),mmd->getOuterScope())); - writeMultiLineCodeLink(ol,mmd,clName); - addToSearchIndex(className); - const Definition *d = mmd->getOuterScope()==Doxygen::globalScope ? - mmd->getBodyDef() : mmd->getOuterScope(); - if (mmd->getGroupDef()) d = mmd->getGroupDef(); - if (d && d->isLinkable() && mmd->isLinkable() && - g_currentMemberDef && g_collectXRefs) - { - addDocCrossReference(g_currentMemberDef,mmd); - } - return; - } + MemberDef *mmd = mcd->getMemberByName(locName); + if (mmd) + { + yyextra->theCallContext.setClass(stripClassName(yyscanner,mmd->typeString(),mmd->getOuterScope())); + writeMultiLineCodeLink(yyscanner,ol,mmd,clName); + addToSearchIndex(yyscanner,className); + const Definition *d = mmd->getOuterScope()==Doxygen::globalScope ? + mmd->getBodyDef() : mmd->getOuterScope(); + if (mmd->getGroupDef()) d = mmd->getGroupDef(); + if (d && d->isLinkable() && mmd->isLinkable() && + yyextra->currentMemberDef && yyextra->collectXRefs) + { + addDocCrossReference(yyextra->currentMemberDef,mmd); + } + return; + } } else // check namespace as well { const NamespaceDef *mnd = getResolvedNamespace(scope); if (mnd) { - MemberDef *mmd=mnd->getMemberByName(locName); - if (mmd) + MemberDef *mmd=mnd->getMemberByName(locName); + if (mmd) { - //printf("name=%s scope=%s\n",locName.data(),scope.data()); - g_theCallContext.setClass(stripClassName(mmd->typeString(),mmd->getOuterScope())); - writeMultiLineCodeLink(ol,mmd,clName); - addToSearchIndex(className); - const Definition *d = mmd->getOuterScope()==Doxygen::globalScope ? - mmd->getBodyDef() : mmd->getOuterScope(); - if (mmd->getGroupDef()) d = mmd->getGroupDef(); - if (d && d->isLinkable() && mmd->isLinkable() && - g_currentMemberDef && g_collectXRefs) - { - addDocCrossReference(g_currentMemberDef,mmd); - } - return; + //printf("name=%s scope=%s\n",locName.data(),scope.data()); + yyextra->theCallContext.setClass(stripClassName(yyscanner,mmd->typeString(),mmd->getOuterScope())); + writeMultiLineCodeLink(yyscanner,ol,mmd,clName); + addToSearchIndex(yyscanner,className); + const Definition *d = mmd->getOuterScope()==Doxygen::globalScope ? + mmd->getBodyDef() : mmd->getOuterScope(); + if (mmd->getGroupDef()) d = mmd->getGroupDef(); + if (d && d->isLinkable() && mmd->isLinkable() && + yyextra->currentMemberDef && yyextra->collectXRefs) + { + addDocCrossReference(yyextra->currentMemberDef,mmd); + } + return; } } } } - + // nothing found, just write out the word - codifyLines(clName); - addToSearchIndex(clName); + codifyLines(yyscanner,clName); + addToSearchIndex(yyscanner,clName); } } +//------------------------------------------------------------------------------- + /* As of June 1, this function seems to work for file members, but scopes are not @@ -750,11 +1498,13 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName, so it doesn't work for classes yet. */ -static void generateFunctionLink(CodeOutputInterface &ol,char *funcName) +static void generateFunctionLink(yyscan_t yyscanner, + CodeOutputInterface &ol, + const char *funcName) { - //CodeClassDef *ccd=0; - ClassDef *ccd=0; - QCString locScope=g_classScope.copy(); + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + const ClassDef *ccd=0; + QCString locScope=yyextra->classScope.copy(); QCString locFunc=removeRedundantWhiteSpace(funcName); DBG_CTX((stdout,"*** locScope=%s locFunc=%s\n",locScope.data(),locFunc.data())); int i=locFunc.findRev("::"); @@ -764,915 +1514,222 @@ static void generateFunctionLink(CodeOutputInterface &ol,char *funcName) locFunc=locFunc.right(locFunc.length()-i-2).stripWhiteSpace(); } //printf("generateFunctionLink(%s) classScope='%s'\n",locFunc.data(),locScope.data()); - if (!locScope.isEmpty() && (ccd=g_codeClassSDict[locScope])) + if (!locScope.isEmpty()) { - //printf("using classScope %s\n",g_classScope.data()); - if (ccd->baseClasses()) + auto it = yyextra->codeClassMap.find(locScope.str()); + if (it!=yyextra->codeClassMap.end()) + { + ccd = it->second.get(); + } + //printf("using classScope %s\n",yyextra->classScope.data()); + if (ccd && ccd->baseClasses()) { BaseClassListIterator bcli(*ccd->baseClasses()); for ( ; bcli.current() ; ++bcli) { - if (getLink(bcli.current()->classDef->name(),locFunc,ol,funcName)) - { - return; - } + if (getLink(yyscanner,bcli.current()->classDef->name(),locFunc,ol,funcName)) + { + return; + } } } } - if (!getLink(locScope,locFunc,ol,funcName)) + if (!getLink(yyscanner,locScope,locFunc,ol,funcName)) { - generateClassOrGlobalLink(ol,funcName); + generateClassOrGlobalLink(yyscanner,ol,funcName); } return; } -static bool findMemberLink(CodeOutputInterface &ol,Definition *sym,const char *symName) +//------------------------------------------------------------------------------- + +static bool findMemberLink(yyscan_t yyscanner, + CodeOutputInterface &ol, + Definition *sym, + const char *symName) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; //printf("sym %s outerScope=%s equal=%d\n", // sym->name().data(),sym->getOuterScope()->name().data(), - // sym->getOuterScope()==g_currentDefinition); + // sym->getOuterScope()==yyextra->currentDefinition); if (sym->getOuterScope() && sym->getOuterScope()->definitionType()==Definition::TypeClass && - g_currentDefinition->definitionType()==Definition::TypeClass) + yyextra->currentDefinition->definitionType()==Definition::TypeClass) { ClassDef *cd = dynamic_cast(sym->getOuterScope()); - ClassDef *thisCd = dynamic_cast(g_currentDefinition); + ClassDef *thisCd = dynamic_cast(yyextra->currentDefinition); if (sym->definitionType()==Definition::TypeMember) { - if (g_currentMemberDef && g_collectXRefs) + if (yyextra->currentMemberDef && yyextra->collectXRefs) { - addDocCrossReference(g_currentMemberDef,dynamic_cast(sym)); + addDocCrossReference(yyextra->currentMemberDef,dynamic_cast(sym)); } } DBG_CTX((stderr,"cd=%s thisCd=%s\n",cd?cd->name().data():"",thisCd?thisCd->name().data():"")); // TODO: find the nearest base class in case cd is a base class of - // thisCd + // thisCd if (cd==thisCd || (thisCd && thisCd->isBaseClass(cd,TRUE))) { - writeMultiLineCodeLink(ol,sym,symName); + writeMultiLineCodeLink(yyscanner,ol,sym,symName); return TRUE; } } return FALSE; } -static void findMemberLink(CodeOutputInterface &ol,char *symName) +//------------------------------------------------------------------------------- + +static void findMemberLink(yyscan_t yyscanner, + CodeOutputInterface &ol, + const char *symName) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; //printf("Member reference: %s scope=%s member=%s\n", // yytext, - // g_currentDefinition?g_currentDefinition->name().data():"", - // g_currentMemberDef?g_currentMemberDef->name().data():"" + // yyextra->currentDefinition?yyextra->currentDefinition->name().data():"", + // yyextra->currentMemberDef?yyextra->currentMemberDef->name().data():"" // ); - if (g_currentDefinition) + if (yyextra->currentDefinition) { DefinitionIntf *di = Doxygen::symbolMap->find(symName); if (di) { if (di->definitionType()==DefinitionIntf::TypeSymbolList) // multiple symbols { - DefinitionListIterator dli(*(DefinitionList*)di); - Definition *sym; - for (dli.toFirst();(sym=dli.current());++dli) - { - if (findMemberLink(ol,sym,symName)) return; - } + DefinitionListIterator dli(*(DefinitionList*)di); + Definition *sym; + for (dli.toFirst();(sym=dli.current());++dli) + { + if (findMemberLink(yyscanner,ol,sym,symName)) return; + } } else // single symbol { - if (findMemberLink(ol,(Definition*)di,symName)) return; + if (findMemberLink(yyscanner,ol,(Definition*)di,symName)) return; } } } //printf("sym %s not found\n",&yytext[5]); - codify(symName); -} - -#undef YY_INPUT -#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); - -static yy_size_t yyread(char *buf,yy_size_t max_size) -{ - yy_size_t c=0; - while( c < max_size && g_inputString[g_inputPosition] ) - { - *buf = g_inputString[g_inputPosition++] ; - c++; buf++; - } - return c; -} - -%} - - -BB [ \t]+ -B [ \t]* -NEWLINE \n - -DIGIT [0-9] -LETTER [A-Za-z\x80-\xFF] -NONEMPTY [A-Za-z0-9_\x80-\xFF] -EXPCHAR [#(){}\[\],:.%/\\=`*~|&<>!;+-] -NONEMPTYEXP [^ \t\n:] -PARAMNONEMPTY [^ \t\n():] -IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")* -BORDER ([^A-Za-z0-9]) - -POUNDCOMMENT "##" - -TRISINGLEQUOTE "'''" -TRIDOUBLEQUOTE "\"\"\"" -LONGSTRINGCHAR [^\\"'] -ESCAPESEQ ("\\")(.) -LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ}) -SMALLQUOTE ("\"\""|"\""|"'"|"''") -LONGSTRINGBLOCK ({LONGSTRINGITEM}+|{SMALLQUOTE}) - -SHORTSTRING ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"') -SHORTSTRINGITEM ({SHORTSTRINGCHAR}|{ESCAPESEQ}) -SHORTSTRINGCHAR [^\\\n"] -STRINGLITERAL {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING}) -STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR") -KEYWORD ("lambda"|"import"|"class"|"assert"|"with"|"as"|"from"|"global"|"def"|"True"|"False") -FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally") -QUOTES ("\""[^"]*"\"") -SINGLEQUOTES ("'"[^']*"'") - -LONGINTEGER {INTEGER}("l"|"L") -INTEGER ({DECIMALINTEGER}|{OCTINTEGER}|{HEXINTEGER}) -DECIMALINTEGER ({NONZERODIGIT}{DIGIT}*|"0") -OCTINTEGER "0"{OCTDIGIT}+ -HEXINTEGER "0"("x"|"X"){HEXDIGIT}+ -NONZERODIGIT [1-9] -OCTDIGIT [0-7] -HEXDIGIT ({DIGIT}|[a-f]|[A-F]) -FLOATNUMBER ({POINTFLOAT}|{EXPONENTFLOAT}) -POINTFLOAT ({INTPART}?{FRACTION}|{INTPART}".") -EXPONENTFLOAT ({INTPART}|{POINTFLOAT}){EXPONENT} -INTPART {DIGIT}+ -FRACTION "."{DIGIT}+ -EXPONENT ("e"|"E")("+"|"-")?{DIGIT}+ -IMAGNUMBER ({FLOATNUMBER}|{INTPART})("j"|"J") -ATOM ({IDENTIFIER}|{LITERAL}|{ENCLOSURE}) -ENCLOSURE ({PARENTH_FORM}|{LIST_DISPLAY}|{DICT_DISPLAY}|{STRING_CONVERSION}) -LITERAL ({STRINGLITERAL}|{INTEGER}|{LONGINTEGER}|{FLOATNUMBER}|{IMAGNUMBER}) -PARENTH_FORM "("{EXPRESSION_LIST}?")" -TEST ({AND_TEST}("or"{AND_TEST})*|{LAMBDA_FORM}) -TESTLIST {TEST}( ","{TEST})*","? -LIST_DISPLAY "["{LISTMAKER}?"]" -LISTMAKER {EXPRESSION}({LIST_FOR}|(","{EXPRESSION})*","?) -LIST_ITER ({LIST_FOR}|{LIST_IF}) -LIST_FOR "for"{EXPRESSION_LIST}"in"{TESTLIST}{LIST_ITER}? -LIST_IF "if"{TEST}{LIST_ITER}? -DICT_DISPLAY "\{"{KEY_DATUM_LIST}?"\}" -KEY_DATUM_LIST {KEY_DATUM}(","{KEY_DATUM})*","? -KEY_DATUM {EXPRESSION}":"{EXPRESSION} -STRING_CONVERSION "`"{EXPRESSION_LIST}"`" -PRIMARY ({ATOM}|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}|{CALL}) -ATTRIBUTEREF {PRIMARY}"."{IDENTIFIER} -SUBSCRIPTION {PRIMARY}"["{EXPRESSION_LIST}"]" -SLICING ({SIMPLE_SLICING}|{EXTENDED_SLICING}) -SIMPLE_SLICING {PRIMARY}"["{SHORT_SLICE}"]" -EXTENDED_SLICING {PRIMARY}"["{SLICE_LIST}"]" -SLICE_LIST {SLICE_ITEM}(","{SLICE_ITEM})*","? -SLICE_ITEM ({EXPRESSION}|{PROPER_SLICE}|{ELLIPSIS}) -PROPER_SLICE ({SHORT_SLICE}|{LONG_SLICE}) -SHORT_SLICE {LOWER_BOUND}?":"{UPPER_BOUND}? -LONG_SLICE {SHORT_SLICE}":"{STRIDE}? -LOWER_BOUND {EXPRESSION} -UPPER_BOUND {EXPRESSION} -STRIDE {EXPRESSION} -ELLIPSIS "..." -CALL {PRIMARY}"("({ARGUMENT_LIST}","?)?")" -ARGUMENT_LIST ({POSITIONAL_ARGUMENTS}(","{KEYWORD_ARGUMENTS})?(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|{KEYWORD_ARGUMENTS}(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|"*"{EXPRESSION}(",""**"{EXPRESSION})?|"**"{EXPRESSION}) -POSITIONAL_ARGUMENTS {EXPRESSION}(","{EXPRESSION})* -KEYWORD_ARGUMENTS {KEYWORD_ITEM}(","{KEYWORD_ITEM})* -KEYWORD_ITEM {IDENTIFIER}"="{EXPRESSION} -POWER {PRIMARY}("**"{U_EXPR})? -U_EXPR ({POWER}|"-"{U_EXPR}|"+"{U_EXPR}|"\~"{U_EXPR}) -M_EXPR ({U_EXPR}|{M_EXPR}"*"{U_EXPR}|{M_EXPR}"//"{U_EXPR}|{M_EXPR}"/"{U_EXPR}|{M_EXPR}"\%"{U_EXPR}) -A_EXPR ({M_EXPR}|{A_EXPR}"+"{M_EXPR}|{A_EXPR}"-"{M_EXPR} -SHIFT_EXPR ({A_EXPR}|{SHIFT_EXPR}("<<"|">>"){A_EXPR}) -AND_EXPR ({SHIFT_EXPR}|{AND_EXPR}"\;SPMamp;"{SHIFT_EXPR} -XOR_EXPR ({AND_EXPR}|{XOR_EXPR}"\textasciicircum"{AND_EXPR}) -OR_EXPR ({XOR_EXPR}|{OR_EXPR}"|"{ XOR_EXPR}) - -COMPARISON {OR_EXPR}({COMP_OPERATOR}{OR_EXPR})* -COMP_OPERATOR ("<"|">"|"=="|">="|"<="|"<>"|"!="|"is""not"?|"not"?"in") -EXPRESSION ({OR_TEST}|{LAMBDA_FORM}) -OR_TEST ({AND_TEST}|{OR_TEST}"or"{AND_TEST}) -AND_TEST ({NOT_TEST}|{AND_TEST}"and"{NOT_TEST}) -NOT_TEST ({COMPARISON}|"not"{NOT_TEST}) -LAMBDA_FORM "lambda"{PARAMETER_LIST}?":"{EXPRESSION} -EXPRESSION_LIST {EXPRESSION}(","{EXPRESSION})*","? -SIMPLE_STMT ({EXPRESSION_STMT}|{ASSERT_STMT}|{ASSIGNMENT_STMT}|{AUGMENTED_ASSIGNMENT_STMT}|{PASS_STMT}|{DEL_STMT}|{PRINT_STMT}|{RETURN_STMT}|{YIELD_STMT}|{RAISE_STMT}|{BREAK_STMT}|{CONTINUE_STMT}|{IMPORT_STMT}|{GLOBAL_STMT}|{EXEC_STMT}) -EXPRESSION_STMT {EXPRESSION_LIST} -ASSERT_STMT "assert"{EXPRESSION}(","{EXPRESSION})? -ASSIGNMENT_STMT ({TARGET_LIST}"=")+{EXPRESSION_LIST} -TARGET_LIST {TARGET}(","{TARGET})*","? -TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}) - - -%option noyywrap -%option stack - -%x Body - -%x FunctionDec -%x FunctionParams - -%x ClassDec -%x ClassInheritance - -%x Suite -%x SuiteCaptureIndent -%x SuiteStart -%x SuiteMaintain -%x SuiteContinuing - -%x LongString - -%x SingleQuoteString -%x DoubleQuoteString -%x TripleString - -%x DocBlock -%% - -{ - "def"{BB} { - startFontClass("keyword"); - codify(yytext); - endFontClass(); - BEGIN( FunctionDec ); - } - - "class"{BB} { - startFontClass("keyword"); - codify(yytext); - endFontClass(); - BEGIN( ClassDec ); - } - "None" { - startFontClass("keywordtype"); - codify(yytext); - endFontClass(); - } - "self."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER}"(" { - codify("self."); - findMemberLink(*g_code,&yytext[5]); - } - "self."{IDENTIFIER}/"(" { - codify("self."); - findMemberLink(*g_code,&yytext[5]); - } - "self."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER} { - codify("self."); - findMemberLink(*g_code,&yytext[5]); - } - "self."{IDENTIFIER} { - codify("self."); - findMemberLink(*g_code,&yytext[5]); - } - "cls."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER}"(" { - codify("cls."); - findMemberLink(*g_code,&yytext[4]); - } - "cls."{IDENTIFIER}/"(" { - codify("cls."); - findMemberLink(*g_code,&yytext[4]); - } - "cls."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER} { - codify("cls."); - findMemberLink(*g_code,&yytext[4]); - } - "cls."{IDENTIFIER} { - codify("cls."); - findMemberLink(*g_code,&yytext[4]); - } -} - -{IDENTIFIER} { - - generateClassOrGlobalLink(*g_code,yytext); - // codify(yytext); - g_curClassName = yytext; - g_curClassBases.clear(); - BEGIN( ClassInheritance ); - } - -{ - ({BB}|[(,)]) { - codify(yytext); - } - - ({IDENTIFIER}".")*{IDENTIFIER} { - // The parser - // is assuming - // that ALL identifiers - // in this state - // are base classes; - // it doesn't check to see - // that the first parenthesis - // has been seen. - - // This is bad - it should - // probably be more strict - // about what to accept. - - g_curClassBases.inSort(yytext); - generateClassOrGlobalLink(*g_code,yytext); - // codify(yytext); - } - - ":" { - codify(yytext); - - // Assume this will - // be a one-line suite; - // found counter-example - // in SuiteStart. - - // Push a class scope - - ClassDef *classDefToAdd = createClassDef("",1,1,g_curClassName,ClassDef::Class,0,0,FALSE); - g_codeClassSDict.append(g_curClassName,classDefToAdd); - char *s=g_curClassBases.first(); - while (s) - { - const ClassDef *baseDefToAdd=g_codeClassSDict[s]; - - // Try to find class in global - // scope - if (baseDefToAdd==0) - { - baseDefToAdd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s); - } - - if (baseDefToAdd && baseDefToAdd!=classDefToAdd) - { - classDefToAdd->insertBaseClass(const_cast(baseDefToAdd),s,Public,Normal); - } - - s=g_curClassBases.next(); - } - - // Reset class-parsing variables. - g_curClassName.resize(0); - g_curClassBases.clear(); - - g_noSuiteFound = TRUE; - BEGIN( SuiteStart ); - } -} - - -{ - {IDENTIFIER} { - generateFunctionLink(*g_code,yytext); - } - - {B}"(" { - codify(yytext); - BEGIN( FunctionParams ); - } -} - -{ - ({BB}|",") { - // Parses delimiters - codify(yytext); - } - - ({IDENTIFIER}|{PARAMNONEMPTY}+) { - codify(yytext); - } - - ")" { - codify(yytext); - } - - "\n" { - codifyLines(yytext); - } - - ":" { - codify(yytext); - - // Assume this will - // be a one-line suite; - // found counter-example - // in SuiteStart. - g_noSuiteFound = TRUE; - BEGIN( SuiteStart ); - } -} - -{ - - {KEYWORD} { - // Position-sensitive rules! - // Must come AFTER keyword-triggered rules - // Must come BEFORE identifier NONEMPTY-like rules - // to syntax highlight. - - startFontClass("keyword"); - codify(yytext); - endFontClass(); - } - - {FLOWKW} { - if (g_currentMemberDef && g_currentMemberDef->isFunction()) - { - g_currentMemberDef->incrementFlowKeyWordCount(); - } - startFontClass("keywordflow"); - codify(yytext); - endFontClass(); - } - ({IDENTIFIER}".")*{IDENTIFIER}/"(" { - generateClassOrGlobalLink(*g_code,yytext); - } - ({IDENTIFIER}".")+{IDENTIFIER} { - generateClassOrGlobalLink(*g_code,yytext,TRUE); - } - {IDENTIFIER} { codify(yytext); } - -} - - - -{ - - {BB} { - codify(yytext); - } - "pass" { - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - BEGIN(Body); - } - {KEYWORD} { - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - - // No indentation necessary - g_noSuiteFound = FALSE; - } - - {FLOWKW} { - if (g_currentMemberDef && g_currentMemberDef->isFunction()) - { - g_currentMemberDef->incrementFlowKeyWordCount(); - } - startFontClass("keywordflow"); - codifyLines(yytext); - endFontClass(); - - // No indentation necessary - g_noSuiteFound = FALSE; - } - {IDENTIFIER} { - codify(yytext); - } - - - {POUNDCOMMENT} { - if (YY_START==SingleQuoteString || - YY_START==DoubleQuoteString || - YY_START==TripleString - ) - { - REJECT; - } - yy_push_state(YY_START); - BEGIN(DocBlock); - g_docBlock=yytext; - } - - {NEWLINE} { - codifyLines(yytext); - if ( g_noSuiteFound ) - { - // printf("New suite to capture! [%d]\n", g_yyLineNr); - BEGIN ( SuiteCaptureIndent ); - } - } -} - -{ - "\n"|({BB}"\n") { - // Blankline - ignore, keep looking for indentation. - codifyLines(yytext); - } - - {BB} { - // This state lasts momentarily, - // to check the indentation - // level that is about to be - // used. - codifyLines(yytext); - g_indents.push(static_cast(yyleng)); - // printf("Captured indent of %d [line %d]\n", yyleng, g_yyLineNr); - BEGIN( Suite ); - } -} - -{ - - {BB}/({NONEMPTY}|{EXPCHAR}) { - // This implements poor - // indentation-tracking; - // should be improved. - // (translate tabs to space, etc) - codifyLines(yytext); - adjustScopesAndSuites(static_cast(yyleng)); - } - - "\n"|({BB}"\n") { - // If this ever succeeds, - // it means that this is - // a blank line, and - // can be ignored. - codifyLines(yytext); - } - - ""/({NONEMPTY}|{EXPCHAR}) { - // Default rule; matches - // the empty string, assuming - // real text starts here. - // Just go straight to Body. - adjustScopesAndSuites(0); - } + codify(yyscanner,symName); } -{NEWLINE} { - codifyLines(yytext); - BEGIN( SuiteMaintain ); - } -{IDENTIFIER} { - codify(yytext); - } -{NEWLINE} { - codifyLines(yytext); - } +//------------------------------------------------------------------------------- -{ // Single quoted string like 'That\'s a """nice""" string!' - \\{B}\n { // line continuation - codifyLines(yytext); - } - \\. { // escaped char - codify(yytext); - } - {STRINGPREFIX}?{TRIDOUBLEQUOTE} { // triple double quotes - codify(yytext); - } - "'" { // end of the string - codify(yytext); - endFontClass(); - BEGIN(g_stringContext); - } - [^"'\n\\]+ { // normal chars - codify(yytext); - } - . { // normal char - codify(yytext); - } -} - -{ // Double quoted string like "That's \"a '''nice'''\" string!" - \\{B}\n { // line continuation - codifyLines(yytext); - } - \\. { // escaped char - codify(yytext); - } - {STRINGPREFIX}?{TRISINGLEQUOTE} { // triple single quotes - codify(yytext); - } - "\"" { // end of the string - codify(yytext); - endFontClass(); - BEGIN(g_stringContext); - } - [^"'\n\\]+ { // normal chars - codify(yytext); - } - . { // normal char - codify(yytext); - } -} +struct PythonCodeParser::Private +{ + yyscan_t yyscanner; + pycodeYY_state state; +}; -{ - {TRIDOUBLEQUOTE} | - {TRISINGLEQUOTE} { - codify(yytext); - if (g_doubleQuote==(yytext[0]=='"')) - { - endFontClass(); - BEGIN(g_stringContext); - } - } - {LONGSTRINGBLOCK} { - codifyLines(yytext); - } - \n { - codifyLines(yytext); - } - . { - codify(yytext); - } +PythonCodeParser::PythonCodeParser() : p(std::make_unique()) +{ + pycodeYYlex_init_extra(&p->state,&p->yyscanner); +#ifdef FLEX_DEBUG + pycodeYYset_debug(1,p->yyscanner); +#endif + resetCodeParserState(); } - /* -<*>({NONEMPTY}|{EXPCHAR}|{BB}) { // This should go one character at a time. - codify(yytext); - // printf("[pycode] '%s' [ state %d ] [line %d] no match\n", - // yytext, YY_START, g_yyLineNr); - - //endFontClass(); - BEGIN(Body); - } - */ - -<*>{STRINGPREFIX}?{TRISINGLEQUOTE} { - if (YY_START==SingleQuoteString) REJECT; - startFontClass("stringliteral"); - g_stringContext=YY_START; - g_doubleQuote=yytext[yyleng-1]=='"'; - codify(yytext); - BEGIN(TripleString); - } -<*>{STRINGPREFIX}?{TRIDOUBLEQUOTE} { - if (YY_START==DoubleQuoteString) REJECT; - startFontClass("stringliteral"); - g_stringContext=YY_START; - g_doubleQuote=yytext[yyleng-1]=='"'; - codify(yytext); - BEGIN(TripleString); - } -<*>{STRINGPREFIX}?"'" { // single quoted string - if (YY_START==SingleQuoteString || - YY_START==DoubleQuoteString || - YY_START==TripleString - ) - { - REJECT; - } - startFontClass("stringliteral"); - g_stringContext=YY_START; - codify(yytext); - BEGIN(SingleQuoteString); - } -<*>{STRINGPREFIX}?"\"" { // double quoted string - if (YY_START==SingleQuoteString || - YY_START==DoubleQuoteString || - YY_START==TripleString - ) - { - REJECT; - } - startFontClass("stringliteral"); - g_stringContext=YY_START; - codify(yytext); - BEGIN(DoubleQuoteString); - } -.* { // contents of current comment line - g_docBlock+=yytext; - } -"\n"{B}("#") { // comment block (next line is also comment line) - g_docBlock+=yytext; - } -{NEWLINE} { // comment block ends at the end of this line - // remove special comment (default config) - if (Config_getBool(STRIP_CODE_COMMENTS)) - { - g_yyLineNr+=((QCString)g_docBlock).contains('\n'); - g_endComment=TRUE; - } - else // do not remove comment - { - startFontClass("comment"); - codifyLines(g_docBlock); - endFontClass(); - } - unput(*yytext); - yy_pop_state(); - } -<*>{POUNDCOMMENT}.* { - if (YY_START==SingleQuoteString || - YY_START==DoubleQuoteString || - YY_START==TripleString - ) - { - REJECT; - } - yy_push_state(YY_START); - BEGIN(DocBlock); - g_docBlock=yytext; - } -<*>"#".* { // normal comment - if (YY_START==SingleQuoteString || - YY_START==DoubleQuoteString || - YY_START==TripleString - ) - { - REJECT; - } - startFontClass("comment"); - codifyLines(yytext); - endFontClass(); - } -<*>{NEWLINE} { - if (g_endComment) - { - g_endComment=FALSE; - } - else - { - codifyLines(yytext); - } - //printf("[pycode] %d NEWLINE [line %d] no match\n", - // YY_START, g_yyLineNr); - - //endFontClass(); - BEGIN(Body); - } - -<*>[ \t]+ { - codify(yytext); - BEGIN(Body); - } -<*>. { - codify(yytext); - // printf("[pycode] '%s' [ state %d ] [line %d] no match\n", - // yytext, YY_START, g_yyLineNr); - - //endFontClass(); - BEGIN(Body); - } - -<*><> { - if (YY_START == DocBlock) { - if (!Config_getBool(STRIP_CODE_COMMENTS)) - { - startFontClass("comment"); - codifyLines(g_docBlock); - endFontClass(); - } - } - yyterminate(); - } -%% - -/*@ ---------------------------------------------------------------------------- - */ - -void resetPythonCodeParserState() +PythonCodeParser::~PythonCodeParser() { - g_codeClassSDict.setAutoDelete(TRUE); - g_codeClassSDict.clear(); - g_currentDefinition = 0; - g_currentMemberDef = 0; - g_doubleStringIsDoc = FALSE; - g_paramParens = 0; - g_indents.clear(); - BEGIN( Body ); + pycodeYYlex_destroy(p->yyscanner); } -/*! - Examines current stack of white-space indentations; - re-syncs the parser with the correct scope. -*/ -static void adjustScopesAndSuites(unsigned indentLength) +void PythonCodeParser::resetCodeParserState() { - // States to pop - if (!g_indents.isEmpty() && indentLength < g_indents.top()) - { - while (!g_indents.isEmpty() && indentLength < g_indents.top()) - { - // printf("Exited scope indent of [%d]\n", g_indents.top()); - g_indents.pop(); // Pop the old suite's indentation - - g_currentMemberDef=0; - if (g_currentDefinition) - g_currentDefinition=g_currentDefinition->getOuterScope(); - } - } - - // Are there any remaining indentation levels for suites? - if (!g_indents.isEmpty()) - { - BEGIN( Suite ); - } - else - { - BEGIN( Body ); - } + struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; + yyextra->codeClassMap.clear(); + yyextra->currentDefinition = 0; + yyextra->currentMemberDef = 0; + yyextra->doubleStringIsDoc = FALSE; + yyextra->paramParens = 0; + while (!yyextra->indents.empty()) yyextra->indents.pop(); + BEGIN( Body ); } -void parsePythonCode(CodeOutputInterface &od,const char * /*className*/, - const QCString &s,bool exBlock, const char *exName, - FileDef *fd,int startLine,int endLine,bool inlineFragment, - const MemberDef *,bool,const Definition *searchCtx,bool collectXRefs) +void PythonCodeParser::parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + SrcLangExt /*lang*/, + bool isExampleBlock, + const char *exampleName, + FileDef *fileDef, + int startLine, + int endLine, + bool inlineFragment, + const MemberDef *memberDef, + bool showLineNumbers, + const Definition *searchCtx, + bool collectXRefs + ) { + yyscan_t yyscanner = p->yyscanner; + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; //printf("***parseCode()\n"); - - //-------------------------------------- - if (s.isEmpty()) return; - printlex(yy_flex_debug, TRUE, __FILE__, fd ? fd->fileName().data(): NULL); - g_codeClassSDict.setAutoDelete(TRUE); - g_code = &od; - g_inputString = s; - g_inputPosition = 0; - g_currentFontClass = 0; - g_needsTermination = FALSE; - g_searchCtx=searchCtx; - g_collectXRefs=collectXRefs; + + if (input.isEmpty()) return; + printlex(yy_flex_debug, TRUE, __FILE__, fileDef ? fileDef->fileName().data(): NULL); + yyextra->code = &codeOutIntf; + yyextra->inputString = input; + yyextra->inputPosition = 0; + yyextra->currentFontClass = 0; + yyextra->needsTermination = FALSE; + yyextra->searchCtx=searchCtx; + yyextra->collectXRefs=collectXRefs; if (startLine!=-1) - g_yyLineNr = startLine; + yyextra->yyLineNr = startLine; else - g_yyLineNr = 1; + yyextra->yyLineNr = 1; if (endLine!=-1) - g_inputLines = endLine+1; + yyextra->inputLines = endLine+1; else - g_inputLines = g_yyLineNr + countLines() - 1; - - - g_exampleBlock = exBlock; - g_exampleName = exName; - g_sourceFileDef = fd; + yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1; + + + yyextra->exampleBlock = isExampleBlock; + yyextra->exampleName = exampleName; + yyextra->sourceFileDef = fileDef; bool cleanupSourceDef = FALSE; - if (exBlock && fd==0) + if (yyextra->exampleBlock && fileDef==0) { // create a dummy filedef for the example - g_sourceFileDef = createFileDef("",(exName?exName:"generated")); + yyextra->sourceFileDef = createFileDef("",(exampleName?exampleName:"generated")); cleanupSourceDef = TRUE; } - if (g_sourceFileDef) + if (yyextra->sourceFileDef) { - setCurrentDoc("l00001"); + setCurrentDoc(yyscanner,"l00001"); } - g_includeCodeFragment = inlineFragment; - // Starts line 1 on the output - startCodeLine(); + yyextra->includeCodeFragment = inlineFragment; + // Starts line 1 on the output + startCodeLine(yyscanner); - pycodeYYrestart( pycodeYYin ); + pycodeYYrestart(0,yyscanner); - pycodeYYlex(); + pycodeYYlex(yyscanner); - if (!g_indents.isEmpty()) + if (!yyextra->indents.empty()) { // printf("Exited pysourceparser in inconsistent state!\n"); } - if (g_needsTermination) + if (yyextra->needsTermination) { - endCodeLine(); + endCodeLine(yyscanner); } if (cleanupSourceDef) { // delete the temporary file definition used for this example - delete g_sourceFileDef; - g_sourceFileDef=0; + delete yyextra->sourceFileDef; + yyextra->sourceFileDef=0; } - printlex(yy_flex_debug, FALSE, __FILE__, fd ? fd->fileName().data(): NULL); - return; -} - -//---------------------------------------------------------------------------- - -void PythonCodeParser::parseCode(CodeOutputInterface &codeOutIntf, - const char *scopeName, - const QCString &input, - SrcLangExt /*lang*/, - bool isExampleBlock, - const char *exampleName, - FileDef *fileDef, - int startLine, - int endLine, - bool inlineFragment, - const MemberDef *memberDef, - bool showLineNumbers, - const Definition *searchCtx, - bool collectXRefs - ) -{ - ::parsePythonCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, - fileDef,startLine,endLine,inlineFragment,memberDef, - showLineNumbers,searchCtx,collectXRefs); -} - -void PythonCodeParser::resetCodeParserState() -{ - ::resetPythonCodeParserState(); + printlex(yy_flex_debug, FALSE, __FILE__, fileDef ? fileDef->fileName().data(): NULL); } #if USE_STATE2STRING diff --git a/src/pyscanner.l b/src/pyscanner.l index d7996b4..b370515 100644 --- a/src/pyscanner.l +++ b/src/pyscanner.l @@ -651,6 +651,7 @@ STARTDOCSYMS "##" {B}":"{B} { // function without arguments yyextra->specialBlock = TRUE; // expecting a docstring yyextra->bodyEntry = yyextra->current; + yyextra->current->bodyLine = yyextra->yyLineNr; BEGIN(FunctionBody); } @@ -1426,7 +1427,7 @@ STARTDOCSYMS "##" } <*>"'" { - fprintf(stderr,"Quote: %d\n",YY_START); + //fprintf(stderr,"Quote: %d\n",YY_START); } <*>. { @@ -1757,8 +1758,8 @@ static void parseCompounds(yyscan_t yyscanner,std::shared_ptr rt) std::shared_ptr ce = rt->children()[i]; if (!ce->program.isEmpty()) { - //printf("-- %s ---------\n%s\n---------------\n", - // ce->name.data(),ce->program.data()); + //fprintf(stderr,"parseCompounds: -- %s (line %d) ---------\n%s\n---------------\n", + // ce->name.data(), ce->bodyLine, ce->program.data()); // init scanner state yyextra->inputString = ce->program; yyextra->inputPosition = 0; -- cgit v0.12