From 0fc06d657d596adcc289a5f228973ea268efd66d Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Mon, 14 Sep 2020 21:13:58 +0200 Subject: Refactoring: making xmlcode.l reentrant --- src/sqlcode.l | 5 +- src/xmlcode.h | 13 +- src/xmlcode.l | 608 +++++++++++++++++++++++++++++++--------------------------- 3 files changed, 331 insertions(+), 295 deletions(-) diff --git a/src/sqlcode.l b/src/sqlcode.l index 58d8481..1ca9204 100644 --- a/src/sqlcode.l +++ b/src/sqlcode.l @@ -395,9 +395,6 @@ void SQLCodeParser::resetCodeParserState() yyextra->currentMemberDef = 0; } - -//--------------------------------------------------------------------------------- - void SQLCodeParser::parseCode(CodeOutputInterface &codeOutIntf, const char *scopeName, const QCString &input, @@ -417,6 +414,8 @@ void SQLCodeParser::parseCode(CodeOutputInterface &codeOutIntf, yyscan_t yyscanner = p->yyscanner; struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + if (input.isEmpty()) return; + printlex(yy_flex_debug, true, __FILE__, fileDef ? fileDef->fileName().data(): NULL); yyextra->code = &codeOutIntf; diff --git a/src/xmlcode.h b/src/xmlcode.h index 4cada9b..5a35506 100644 --- a/src/xmlcode.h +++ b/src/xmlcode.h @@ -1,12 +1,10 @@ /****************************************************************************** * - * - * - * Copyright (C) 1997-2014 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. * @@ -32,6 +30,8 @@ class Definition; class XMLCodeParser : public CodeParserInterface { public: + XMLCodeParser(); + virtual ~XMLCodeParser(); void parseCode(CodeOutputInterface &codeOutIntf, const char *scopeName, const QCString &input, @@ -48,6 +48,9 @@ class XMLCodeParser : public CodeParserInterface bool collectXRefs=TRUE ); void resetCodeParserState(); + private: + struct Private; + std::unique_ptr p; }; diff --git a/src/xmlcode.l b/src/xmlcode.l index b583bf5..c91a00e 100644 --- a/src/xmlcode.l +++ b/src/xmlcode.l @@ -1,10 +1,10 @@ /****************************************************************************** * - * Copyright (C) 1997-2014 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. * @@ -19,6 +19,11 @@ %option never-interactive %option prefix="xmlcodeYY" +%option reentrant +%option extra-type="struct xmlcodeYY_state *" +%option noyy_top_state +%option nounput +%option noyywrap %top{ #include } @@ -44,401 +49,430 @@ #define YY_NO_INPUT 1 #define YY_NO_UNISTD_H 1 -static CodeOutputInterface * g_code; -static QCString g_curClassName; -static QCString g_parmType; -static QCString g_parmName; -static const char * g_inputString; //!< the code fragment as text -static int g_inputPosition; //!< read offset during parsing -static int g_inputLines; //!< number of line in the code fragment -static int g_yyLineNr; //!< current line number -static bool g_needsTermination; -static const Definition *g_searchCtx; - -static bool g_exampleBlock; -static QCString g_exampleName; -static QCString g_exampleFile; - -static QCString g_type; -static QCString g_name; -static QCString g_args; -static QCString g_classScope; - -static QCString g_CurrScope; - -static FileDef * g_sourceFileDef; -static Definition * g_currentDefinition; -static MemberDef * g_currentMemberDef; -static bool g_includeCodeFragment; -static const char * g_currentFontClass; +struct xmlcodeYY_state +{ + CodeOutputInterface * code; + QCString curClassName; + QCString parmType; + QCString parmName; + const char * inputString = 0; //!< the code fragment as text + int inputPosition = 0; //!< read offset during parsing + int inputLines = 0; //!< number of line in the code fragment + int yyLineNr = 0; //!< current line number + bool needsTermination = false; + const Definition *searchCtx = 0; + + bool exampleBlock = false; + QCString exampleName; + QCString exampleFile; + + QCString type; + QCString name; + QCString args; + QCString classScope; + + QCString CurrScope; + + const FileDef * sourceFileDef = 0; + const Definition * currentDefinition = 0; + const MemberDef * currentMemberDef = 0; + bool includeCodeFragment = false; + const char * currentFontClass = 0; +}; #if USE_STATE2STRING static const char *stateToString(int state); #endif -static void codify(const char* text) -{ - g_code->codify(text); +static void codify(yyscan_t yyscanner,const char* text); +static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor); +static void startCodeLine(yyscan_t yyscanner); +static void endFontClass(yyscan_t yyscanner); +static void endCodeLine(yyscan_t yyscanner); +static void nextCodeLine(yyscan_t yyscanner); +static void codifyLines(yyscan_t yyscanner,const char *text); +static void startFontClass(yyscan_t yyscanner,const char *s); +static int countLines(yyscan_t yyscanner); +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); + +%} + +nl (\r\n|\r|\n) +ws [ \t]+ +open "<" +close ">" +namestart [A-Za-z\200-\377_] +namechar [:A-Za-z\200-\377_0-9.-] +esc "&#"[0-9]+";"|"&#x"[0-9a-fA-F]+";" +name {namestart}{namechar}* +comment {open}"!--"([^-]|"-"[^-])*"--"{close} +data "random string" +string \"([^"&]|{esc})*\"|\'([^'&]|{esc})*\' + +%option noyywrap +%option nounput + +%% + +{ws} { + codifyLines(yyscanner,yytext); + } +"/" { + endFontClass(yyscanner); + codify(yyscanner,yytext); + } +"=" { + endFontClass(yyscanner); + codify(yyscanner,yytext); + } +{close} { + endFontClass(yyscanner); + codify(yyscanner,yytext); + } +{name} { + startFontClass(yyscanner,"keyword"); + codify(yyscanner,yytext); + endFontClass(yyscanner); + } +{string} { + startFontClass(yyscanner,"stringliteral"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } + +{open}{ws}?{name} { + // Write the < in a different color + char openBracket[] = { yytext[0], '\0' }; + codify(yyscanner,openBracket); + + // Then write the rest + yytext++; + startFontClass(yyscanner,"keywordtype"); + codify(yyscanner,yytext); + endFontClass(yyscanner); + + BEGIN(INITIAL); + } +{open}{ws}?"/"{name} { + // Write the "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; +} + +static void codify(yyscan_t yyscanner,const char* text) +{ + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + yyextra->code->codify(text); } -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); } } } -/*! start a new line of code, inserting a line number if g_sourceFileDef - * is TRUE. If a definition starts at the current line, then the line +/*! 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_sourceFileDef) - { - Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr); - - if (!g_includeCodeFragment && d && d->isLinkableInProject()) + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + if (yyextra->sourceFileDef) + { + Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr); + + if (!yyextra->includeCodeFragment && d && d->isLinkableInProject()) { - g_currentDefinition = d; - g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr); - //g_insideBody = FALSE; - g_classScope = d->name().copy(); + yyextra->currentDefinition = d; + yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr); + //yyextra->insideBody = false; + yyextra->classScope = d->name().copy(); 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(), + yyextra->code->writeLineNumber(d->getReference(), d->getOutputFileBase(), - 0,g_yyLineNr); - setCurrentDoc(lineAnchor); + 0,yyextra->yyLineNr); + setCurrentDoc(yyscanner,lineAnchor); } } else { - g_code->writeLineNumber(0,0,0,g_yyLineNr); + yyextra->code->writeLineNumber(0,0,0,yyextra->yyLineNr); } } - - 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 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 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); } } -static void codifyLines(char *text) +static void codifyLines(yyscan_t yyscanner,const char *text) { - char *p=text,*sp=p; + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + const char *p=text,*sp=p; char c; - bool done=FALSE; - + bool done=false; while (!done) { sp=p; - while ((c=*p++) && c!='\n') { } - if (c=='\n') { - g_yyLineNr++; - *(p-1)='\0'; - g_code->codify(sp); - nextCodeLine(); + yyextra->yyLineNr++; + int l = (int)(p-sp-1); + char *tmp = (char*)malloc(l+1); + tmp[l]='\0'; + yyextra->code->codify(tmp); + free(tmp); + nextCodeLine(yyscanner); } else { - g_code->codify(sp); - done=TRUE; + yyextra->code->codify(sp); + done=true; } } } -static void startFontClass(const char *s) +static void startFontClass(yyscan_t yyscanner,const char *s) { - endFontClass(); - g_code->startFontClass(s); - g_currentFontClass=s; + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + endFontClass(yyscanner); + yyextra->code->startFontClass(s); + yyextra->currentFontClass=s; } /*! 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; } -#undef YY_INPUT -#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); +//---------------------------------------------------------------------------------------- -static int yyread(char *buf,int max_size) +struct XMLCodeParser::Private { - int c=0; - while( c < max_size && g_inputString[g_inputPosition] ) - { - *buf = g_inputString[g_inputPosition++] ; - c++; buf++; - } - return c; -} - -%} + yyscan_t yyscanner; + xmlcodeYY_state state; +}; -nl (\r\n|\r|\n) -ws [ \t]+ -open "<" -close ">" -namestart [A-Za-z\200-\377_] -namechar [:A-Za-z\200-\377_0-9.-] -esc "&#"[0-9]+";"|"&#x"[0-9a-fA-F]+";" -name {namestart}{namechar}* -comment {open}"!--"([^-]|"-"[^-])*"--"{close} -data "random string" -string \"([^"&]|{esc})*\"|\'([^'&]|{esc})*\' - -%option noyywrap -%option nounput +XMLCodeParser::XMLCodeParser() : p(std::make_unique()) +{ + xmlcodeYYlex_init_extra(&p->state,&p->yyscanner); +#ifdef FLEX_DEBUG + xmlcodeYYset_debug(1,yyscanner); +#endif + resetCodeParserState(); +} -%% +XMLCodeParser::~XMLCodeParser() +{ + xmlcodeYYlex_destroy(p->yyscanner); +} -{ws} { - codifyLines(yytext); - } -"/" { - endFontClass(); - codify(yytext); - } -"=" { - endFontClass(); - codify(yytext); - } -{close} { - endFontClass(); - codify(yytext); - } -{name} { - startFontClass("keyword"); - codify(yytext); - endFontClass(); - } -{string} { - startFontClass("stringliteral"); - codifyLines(yytext); - endFontClass(); - } - -{open}{ws}?{name} { - // Write the < in a different color - char openBracket[] = { yytext[0], '\0' }; - codify(openBracket); - - // Then write the rest - yytext++; - startFontClass("keywordtype"); - codify(yytext); - endFontClass(); - - BEGIN(INITIAL); - } -{open}{ws}?"/"{name} { - // Write the "yyscanner; + yyextra->currentDefinition = 0; + yyextra->currentMemberDef = 0; +} - BEGIN(INITIAL); - } -{comment} { - // Strip off the extra '!' - // yytext++; // < - // *yytext = '<'; // replace '!' with '<' +void XMLCodeParser::parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + SrcLangExt, + 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; - startFontClass("comment"); - codifyLines(yytext); - endFontClass(); - } -{nl} { - codifyLines(yytext); - } + if (input.isEmpty()) return; -. { - //printf("!ERROR(%c)\n", *yytext); - codifyLines(yytext); - } + 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; -void parseXmlCode( - 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*/ - ) -{ - if (s.isEmpty()) return; - printlex(yy_flex_debug, TRUE, __FILE__, fd ? fd->fileName().data(): NULL); - - g_code = &od; - g_inputString = s; - g_inputPosition = 0; - g_currentFontClass = 0; - g_needsTermination = FALSE; - g_searchCtx=searchCtx; - 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; - - bool cleanupSourceDef = FALSE; - - if (exBlock && fd==0) + yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1; + + yyextra->exampleBlock = isExampleBlock; + yyextra->exampleName = exampleName; + yyextra->sourceFileDef = fileDef; + + bool cleanupSourceDef = false; + + if (isExampleBlock && fileDef==0) { // create a dummy filedef for the example - g_sourceFileDef = createFileDef("",(exName?exName:"generated")); - cleanupSourceDef = TRUE; + 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); - xmlcodeYYrestart( xmlcodeYYin ); + xmlcodeYYrestart( 0, yyscanner ); - xmlcodeYYlex(); + xmlcodeYYlex(yyscanner); - 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 resetXmlCodeParserState() -{ - g_currentDefinition = 0; - g_currentMemberDef = 0; -} - -//---------------------------------------------------------------------------- -void XMLCodeParser::parseCode(CodeOutputInterface &codeOutIntf, - const char *scopeName, - const QCString &input, - SrcLangExt, - bool isExampleBlock, - const char *exampleName, - FileDef *fileDef, - int startLine, - int endLine, - bool inlineFragment, - const MemberDef *memberDef, - bool showLineNumbers, - const Definition *searchCtx, - bool collectXRefs - ) -{ - parseXmlCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, - fileDef,startLine,endLine,inlineFragment,memberDef, - showLineNumbers,searchCtx,collectXRefs); + printlex(yy_flex_debug, false, __FILE__, fileDef ? fileDef->fileName().data(): NULL); } -void XMLCodeParser::resetCodeParserState() -{ - resetXmlCodeParserState(); -} #if USE_STATE2STRING #include "xmlcode.l.h" -- cgit v0.12