diff options
-rw-r--r-- | src/code.l | 1 | ||||
-rw-r--r-- | src/fortrancode.h | 15 | ||||
-rw-r--r-- | src/fortrancode.l | 1864 | ||||
-rw-r--r-- | src/fortranscanner.h | 4 | ||||
-rw-r--r-- | src/fortranscanner.l | 3 |
5 files changed, 980 insertions, 907 deletions
@@ -2595,7 +2595,6 @@ static void codifyLines(yyscan_t yyscanner,const char *text) { yyextra->yyLineNr++; yyextra->yyColNr=1; - //*(p-1)='\0'; int l = (int)(p-sp-1); char *tmp = (char*)malloc(l+1); memcpy(tmp,sp,l); diff --git a/src/fortrancode.h b/src/fortrancode.h index 7da6a61..b8cac31 100644 --- a/src/fortrancode.h +++ b/src/fortrancode.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 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. * @@ -26,13 +26,11 @@ class MemberDef; class QCString; class Definition; -void codeFreeScanner(); - - class FortranCodeParser : public CodeParserInterface { public: - FortranCodeParser(FortranFormat format=FortranFormat_Unknown) : m_format(format) { } + FortranCodeParser(FortranFormat format=FortranFormat_Unknown); + virtual ~FortranCodeParser(); void parseCode(CodeOutputInterface &codeOutIntf, const char *scopeName, const QCString &input, @@ -51,7 +49,8 @@ class FortranCodeParser : public CodeParserInterface void resetCodeParserState(); private: - FortranFormat m_format; + struct Private; + std::unique_ptr<Private> p; }; class FortranCodeParserFree : public FortranCodeParser diff --git a/src/fortrancode.l b/src/fortrancode.l index 5d036e8..23beb18 100644 --- a/src/fortrancode.l +++ b/src/fortrancode.l @@ -4,6 +4,7 @@ * * Copyright (C) by Anke Visser * based on the work of Dimitri van Heesch. + * Copyright (C) 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 @@ -25,7 +26,9 @@ **/ %option never-interactive %option case-insensitive +%option reentrant %option prefix="fortrancodeYY" +%option extra-type="struct fortrancodeYY_state *" %option noyy_top_state %top{ #include <stdint.h> @@ -34,7 +37,7 @@ %{ /* - * includes + * includes */ #include <stdio.h> #include <assert.h> @@ -58,6 +61,7 @@ #include "namespacedef.h" #include "tooltip.h" #include "fortrancode.h" +#include "fortranscanner.h" #include "containers.h" const int fixedCommentAfter = 72; @@ -121,217 +125,892 @@ class Scope /*===================================================================*/ /* - * statics + * statics */ -static QCString docBlock; //!< contents of all lines of a documentation block -static QCString currentModule=0; //!< name of the current enclosing module -static QCString currentClass=0; //!< name of the current enclosing class -static UseSDict *useMembers= new UseSDict; //!< info about used modules -static UseEntry *useEntry = 0; //!< current use statement info -static QList<Scope> scopeStack; -static bool g_isExternal = false; -// static QCStringList *currentUseNames= new QCStringList; //! contains names of used modules of current program unit -static QCString g_str=""; //!> contents of fortran string - -static CodeOutputInterface * g_code; - -// TODO: is this still needed? if so, make it work -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 int g_contLineNr; //!< current, local, line number for continuation determination -static int *g_hasContLine = NULL; //!< signals whether or not a line has a continuation line (fixed source form) -static bool g_needsTermination; -static const Definition *g_searchCtx; -static bool g_collectXRefs; -static bool g_isFixedForm; - -static bool g_insideBody; //!< inside subprog/program body? => create links -static const char * g_currentFontClass; - -static bool g_exampleBlock; -static QCString g_exampleName; -static QCString g_exampleFile; - -static FileDef * g_sourceFileDef; -static Definition * g_currentDefinition; -static MemberDef * g_currentMemberDef; -static bool g_includeCodeFragment; - -static char stringStartSymbol; // single or double quote +struct fortrancodeYY_state +{ + QCString docBlock; //!< contents of all lines of a documentation block + QCString currentModule=0; //!< name of the current enclosing module + UseSDict * useMembers= new UseSDict; //!< info about used modules + UseEntry * useEntry = 0; //!< current use statement info + QList<Scope> scopeStack; + bool isExternal = false; + QCString str=""; //!> contents of fortran string + + CodeOutputInterface * code = 0; + + 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 + int contLineNr = 0; //!< current, local, line number for continuation determination + int *hasContLine = 0; //!< signals whether or not a line has a continuation line (fixed source form) + bool needsTermination = false; + const Definition *searchCtx = 0; + bool collectXRefs = false; + bool isFixedForm = false; + + bool insideBody = false; //!< inside subprog/program body? => create links + const char * currentFontClass = 0; + + bool exampleBlock = false; + QCString exampleName; + QCString exampleFile; + + FileDef * sourceFileDef = 0; + Definition * currentDefinition = 0; + MemberDef * currentMemberDef = 0; + bool includeCodeFragment = false; + + char stringStartSymbol = '\0'; // single or double quote // count in variable declaration to filter out // declared from referenced names -static int bracketCount = 0; + int bracketCount = 0; // signal when in type / class /procedure declaration -static int inTypeDecl = 0; + int inTypeDecl = 0; -static bool g_endComment; + bool endComment = false; +}; #if USE_STATE2STRING static const char *stateToString(int state); #endif -static void endFontClass() +static bool getFortranNamespaceDefs(const QCString &mname, + NamespaceDef *&cd); +static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName, + ClassDef *&cd, UseSDict *usedict=0); + +//---------------------------------------------------------------------------- + +static void endFontClass(yyscan_t yyscanner); +static void startFontClass(yyscan_t yyscanner,const char *s); +static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor); +static void addToSearchIndex(yyscan_t yyscanner,const char *text); +static void startCodeLine(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 writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol, + Definition *d,const char *text); +static bool getGenericProcedureLink(yyscan_t yyscanner,const ClassDef *cd, + const char *memberText, + CodeOutputInterface &ol); +static bool getLink(yyscan_t yyscanner,UseSDict *usedict, // dictionary with used modules + const char *memberText, // exact member text + CodeOutputInterface &ol, + const char *text); +static void generateLink(yyscan_t yyscanner,CodeOutputInterface &ol, char *lname); +static int countLines(yyscan_t yyscanner); +static void startScope(yyscan_t yyscanner); +static void endScope(yyscan_t yyscanner); +static void addUse(yyscan_t yyscanner,const QCString &moduleName); +static void addLocalVar(yyscan_t yyscanner,const QCString &varName); +static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName, + UseSDict *usedict=0); +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); + +%} + +IDSYM [a-z_A-Z0-9] +ID [a-z_A-Z]+{IDSYM}* +SUBPROG (subroutine|function) +B [ \t] +BS [ \t]* +BS_ [ \t]+ +COMMA {BS},{BS} +ARGS_L0 ("("[^)]*")") +ARGS_L1a [^()]*"("[^)]*")"[^)]* +ARGS_L1 ("("{ARGS_L1a}*")") +ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")" +ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2}) + +NUM_TYPE (complex|integer|logical|real) +LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.) +KIND {ARGS} +CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS})) +TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE|CLASS|PROCEDURE|ENUMERATOR) + +INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")" +ATTR_SPEC (IMPLICIT|ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|(NON_)?RECURSIVE|PURE|IMPURE|ELEMENTAL|VALUE|NOPASS|DEFERRED|CONTIGUOUS|VOLATILE) +ACCESS_SPEC (PROTECTED|PRIVATE|PUBLIC) +/* Assume that attribute statements are almost the same as attributes. */ +ATTR_STMT {ATTR_SPEC}|DIMENSION +FLOW (DO|SELECT|CASE|SELECT{BS}(CASE|TYPE)|WHERE|IF|THEN|ELSE|WHILE|FORALL|ELSEWHERE|ELSEIF|RETURN|CONTINUE|EXIT|GO{BS}TO) +COMMANDS (FORMAT|CONTAINS|MODULE{BS_}PROCEDURE|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|PRESENT|DEALLOCATE|NULLIFY|SIZE|INQUIRE|OPEN|CLOSE|FLUSH|DATA|COMMON) +IGNORE (CALL) +PREFIX ((NON_)?RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,4}((NON_)?RECURSIVE|IMPURE|PURE|ELEMENTAL)?0 +LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")" + +/* | */ + +%option noyywrap +%option stack +%option caseless +/*%option debug*/ + +%x Start +%x SubCall +%x FuncDef +%x ClassName +%x ClassVar +%x Subprog +%x DocBlock +%x Use +%x UseOnly +%x Import +%x Declaration +%x DeclarationBinding +%x DeclContLine +%x Parameterlist +%x String +%x Subprogend + +%% + /*==================================================================*/ + + /*-------- ignore ------------------------------------------------------------*/ + +<Start>{IGNORE}/{BS}"(" { // do not search keywords, intrinsics... TODO: complete list + codifyLines(yyscanner,yytext); + } + /*-------- inner construct ---------------------------------------------------*/ + +<Start>{COMMANDS}/{BS}[,( \t\n] { // highlight + /* font class is defined e.g. in doxygen.css */ + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<Start>{FLOW}/{BS}[,( \t\n] { + if (yyextra->isFixedForm) + { + if ((yy_my_start == 1) && ((yytext[0] == 'c') || (yytext[0] == 'C'))) YY_FTN_REJECT; + } + if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction()) + { + yyextra->currentMemberDef->incrementFlowKeyWordCount(); + } + /* font class is defined e.g. in doxygen.css */ + startFontClass(yyscanner,"keywordflow"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<Start>{BS}(CASE|CLASS|TYPE){BS_}(IS|DEFAULT) { + startFontClass(yyscanner,"keywordflow"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<Start>{BS}"end"({BS}{FLOW})/[ \t\n] { // list is a bit long as not all have possible end + startFontClass(yyscanner,"keywordflow"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<Start>"implicit"{BS}("none"|{TYPE_SPEC}) { + startFontClass(yyscanner,"keywordtype"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<Start>^{BS}"namelist"/[//] { // Namelist specification + startFontClass(yyscanner,"keywordtype"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } + /*-------- use statement -------------------------------------------*/ +<Start>"use"{BS_} { + startFontClass(yyscanner,"keywordtype"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(Use); + } +<Use>"ONLY" { // TODO: rename + startFontClass(yyscanner,"keywordtype"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(UseOnly); + } +<Use>{ID} { + QCString tmp = yytext; + tmp = tmp.lower(); + yyextra->insideBody=TRUE; + generateLink(yyscanner,*yyextra->code, yytext); + yyextra->insideBody=FALSE; + + /* append module name to use dict */ + yyextra->useEntry = new UseEntry(); + //yyextra->useEntry->module = yytext; + //yyextra->useMembers->append(yytext, yyextra->useEntry); + //addUse(yytext); + yyextra->useEntry->module = tmp; + yyextra->useMembers->append(tmp, yyextra->useEntry); + addUse(yyscanner,tmp); + } +<Use,UseOnly,Import>{BS},{BS} { codifyLines(yyscanner,yytext); } +<UseOnly,Import>{BS}&{BS}"\n" { codifyLines(yyscanner,yytext); + yyextra->contLineNr++; + YY_FTN_RESET} +<UseOnly>{ID} { + QCString tmp = yytext; + tmp = tmp.lower(); + yyextra->useEntry->onlyNames.append(tmp); + yyextra->insideBody=TRUE; + generateLink(yyscanner,*yyextra->code, yytext); + yyextra->insideBody=FALSE; + } +<Use,UseOnly,Import>"\n" { + unput(*yytext); + yy_pop_state(yyscanner); + YY_FTN_RESET + } +<*>"import"{BS}/"\n" | +<*>"import"{BS_} { + startFontClass(yyscanner,"keywordtype"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(Import); + } +<Import>{ID} { + yyextra->insideBody=TRUE; + generateLink(yyscanner,*yyextra->code, yytext); + yyextra->insideBody=FALSE; + } +<Import>("ONLY"|"NONE"|"ALL") { + startFontClass(yyscanner,"keywordtype"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } + /*-------- fortran module -----------------------------------------*/ +<Start>("block"{BS}"data"|"program"|"module"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { // + startScope(yyscanner); + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(ClassName); + if (!qstricmp(yytext,"module")) yyextra->currentModule="module"; + } +<Start>("enum")/{BS_}|{BS}{COMMA}{BS}{LANGUAGE_BIND_SPEC}|\n { // + startScope(yyscanner); + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(ClassName); + } +<*>{LANGUAGE_BIND_SPEC} { // + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<Start>("type")/{BS_}|({COMMA}({ACCESS_SPEC}|ABSTRACT|EXTENDS))|\n { // + startScope(yyscanner); + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(ClassName); + } +<ClassName>{ID} { + if (yyextra->currentModule == "module") + { + yyextra->currentModule=yytext; + yyextra->currentModule = yyextra->currentModule.lower(); + } + generateLink(yyscanner,*yyextra->code,yytext); + yy_pop_state(yyscanner); + } +<ClassName>({ACCESS_SPEC}|ABSTRACT|EXTENDS)/[,:( ] { //| variable declaration + startFontClass(yyscanner,"keyword"); + yyextra->code->codify(yytext); + endFontClass(yyscanner); + } +<ClassName>\n { // interface may be without name + yy_pop_state(yyscanner); + YY_FTN_REJECT; + } +<Start>^{BS}"end"({BS_}"enum").* { + YY_FTN_REJECT; + } +<Start>^{BS}"end"({BS_}"type").* { + YY_FTN_REJECT; + } +<Start>^{BS}"end"({BS_}"module").* { // just reset yyextra->currentModule, rest is done in following rule + yyextra->currentModule=0; + YY_FTN_REJECT; + } + /*-------- subprog definition -------------------------------------*/ +<Start>({PREFIX}{BS_})?{TYPE_SPEC}{BS_}({PREFIX}{BS_})?{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<Start>({PREFIX}{BS_})?{SUBPROG}{BS_} { // Fortran subroutine or function found + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(Subprog); + } +<Subprog>{ID} { // subroutine/function name + DBG_CTX((stderr, "===> start subprogram %s\n", yytext)); + startScope(yyscanner); + generateLink(yyscanner,*yyextra->code,yytext); + } +<Subprog>"result"/{BS}"("[^)]*")" { + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<Subprog>"("[^)]*")" { // ignore rest of line + codifyLines(yyscanner,yytext); + } +<Subprog,Subprogend>"\n" { codifyLines(yyscanner,yytext); + yyextra->contLineNr++; + yy_pop_state(yyscanner); + YY_FTN_RESET + } +<Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface")?{BS} { // Fortran subroutine or function ends + //cout << "===> end function " << yytext << endl; + endScope(yyscanner); + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(Subprogend); + } +<Subprogend>{ID}/{BS}(\n|!|;) { + generateLink(yyscanner,*yyextra->code,yytext); + yy_pop_state(yyscanner); + } +<Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface"){BS}/(\n|!|;) { // Fortran subroutine or function ends + //cout << "===> end function " << yytext << endl; + endScope(yyscanner); + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } + /*-------- variable declaration ----------------------------------*/ +<Start>^{BS}"real"/[,:( ] { // real is a bit tricky as it is a data type but also a function. + yy_push_state(YY_START,yyscanner); + BEGIN(Declaration); + startFontClass(yyscanner,"keywordtype"); + yyextra->code->codify(yytext); + endFontClass(yyscanner); + } +<Start>{TYPE_SPEC}/[,:( ] { + QCString typ = yytext; + typ = removeRedundantWhiteSpace(typ.lower()); + if (typ.startsWith("real")) YY_FTN_REJECT; + if (typ == "type" || typ == "class" || typ == "procedure") yyextra->inTypeDecl = 1; + yy_push_state(YY_START,yyscanner); + BEGIN(Declaration); + startFontClass(yyscanner,"keywordtype"); + yyextra->code->codify(yytext); + endFontClass(yyscanner); + } +<Start>{ATTR_SPEC} { + if (QCString(yytext) == "external") + { + yy_push_state(YY_START,yyscanner); + BEGIN(Declaration); + yyextra->isExternal = true; + } + startFontClass(yyscanner,"keywordtype"); + yyextra->code->codify(yytext); + endFontClass(yyscanner); + } +<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable declaration + if (QCString(yytext) == "external") yyextra->isExternal = true; + startFontClass(yyscanner,"keywordtype"); + yyextra->code->codify(yytext); + endFontClass(yyscanner); + } +<Declaration>{ID} { // local var + if (yyextra->isFixedForm && yy_my_start == 1) + { + startFontClass(yyscanner,"comment"); + yyextra->code->codify(yytext); + endFontClass(yyscanner); + } + else if (yyextra->currentMemberDef && + ((yyextra->currentMemberDef->isFunction() && (yyextra->currentMemberDef->typeString()!=QCString("subroutine") || yyextra->inTypeDecl)) || + yyextra->currentMemberDef->isVariable() || yyextra->currentMemberDef->isEnumValue() + ) + ) + { + generateLink(yyscanner,*yyextra->code, yytext); + } + else + { + yyextra->code->codify(yytext); + addLocalVar(yyscanner,yytext); + } + } +<Declaration>{BS}("=>"|"="){BS} { // Procedure binding + BEGIN(DeclarationBinding); + yyextra->code->codify(yytext); + } +<DeclarationBinding>{ID} { // Type bound procedure link + generateLink(yyscanner,*yyextra->code, yytext); + yy_pop_state(yyscanner); + } +<Declaration>[(] { // start of array or type / class specification + yyextra->bracketCount++; + yyextra->code->codify(yytext); + } + +<Declaration>[)] { // end array specification + yyextra->bracketCount--; + if (!yyextra->bracketCount) yyextra->inTypeDecl = 0; + yyextra->code->codify(yytext); + } + +<Declaration,DeclarationBinding>"&" { // continuation line + yyextra->code->codify(yytext); + if (!yyextra->isFixedForm) + { + yy_push_state(YY_START,yyscanner); + BEGIN(DeclContLine); + } + } +<DeclContLine>"\n" { // declaration not yet finished + yyextra->contLineNr++; + codifyLines(yyscanner,yytext); + yyextra->bracketCount = 0; + yy_pop_state(yyscanner); + YY_FTN_RESET + } +<Declaration,DeclarationBinding>"\n" { // end declaration line (?) + if (yyextra->endComment) + { + yyextra->endComment=FALSE; + } + else + { + codifyLines(yyscanner,yytext); + } + yyextra->bracketCount = 0; + yyextra->contLineNr++; + if (!(yyextra->hasContLine && yyextra->hasContLine[yyextra->contLineNr - 1])) + { + yyextra->isExternal = false; + yy_pop_state(yyscanner); + } + YY_FTN_RESET + } + + /*-------- subprog calls -----------------------------------------*/ + +<Start>"call"{BS_} { + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + yy_push_state(YY_START,yyscanner); + BEGIN(SubCall); + } +<SubCall>{ID} { // subroutine call + yyextra->insideBody=TRUE; + generateLink(yyscanner,*yyextra->code, yytext); + yyextra->insideBody=FALSE; + yy_pop_state(yyscanner); + } +<Start>{ID}{BS}/"(" { // function call + if (yyextra->isFixedForm && yy_my_start == 6) + { + // fixed form continuation line + YY_FTN_REJECT; + } + else if (QCString(yytext).stripWhiteSpace().lower() == "type") + { + yy_push_state(YY_START,yyscanner); + BEGIN(Declaration); + startFontClass(yyscanner,"keywordtype"); + yyextra->code->codify(QCString(yytext).stripWhiteSpace()); + endFontClass(yyscanner); + yyextra->code->codify(yytext + 4); + } + else + { + yyextra->insideBody=TRUE; + generateLink(yyscanner,*yyextra->code, yytext); + yyextra->insideBody=FALSE; + } + } + + /*-------- comments ---------------------------------------------------*/ +<Start,Declaration,DeclarationBinding>\n?{BS}"!>"|"!<" { // start comment line or comment block + if (yytext[0] == '\n') + { + yyextra->contLineNr++; + yy_old_start = 0; + yy_my_start = 1; + yy_end = static_cast<int>(yyleng); + } + // Actually we should see if ! on position 6, can be continuation + // but the chance is very unlikely, so no effort to solve it here + yy_push_state(YY_START,yyscanner); + BEGIN(DocBlock); + yyextra->docBlock=yytext; + } +<Declaration,DeclarationBinding>{BS}"!<" { // start comment line or comment block + yy_push_state(YY_START,yyscanner); + BEGIN(DocBlock); + yyextra->docBlock=yytext; + } + +<DocBlock>.* { // contents of current comment line + yyextra->docBlock+=yytext; + } +<DocBlock>"\n"{BS}("!>"|"!<"|"!!") { // comment block (next line is also comment line) + yyextra->contLineNr++; + yy_old_start = 0; + yy_my_start = 1; + yy_end = static_cast<int>(yyleng); + // Actually we should see if ! on position 6, can be continuation + // but the chance is very unlikely, so no effort to solve it here + yyextra->docBlock+=yytext; + } +<DocBlock>"\n" { // comment block ends at the end of this line + // remove special comment (default config) + yyextra->contLineNr++; + if (Config_getBool(STRIP_CODE_COMMENTS)) + { + yyextra->yyLineNr+=((QCString)yyextra->docBlock).contains('\n'); + yyextra->yyLineNr+=1; + nextCodeLine(yyscanner); + yyextra->endComment=TRUE; + } + else // do not remove comment + { + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yyextra->docBlock); + endFontClass(yyscanner); + } + unput(*yytext); + yyextra->contLineNr--; + yy_pop_state(yyscanner); + YY_FTN_RESET + } + +<*>"!"[^><\n].*|"!"$ { // normal comment + if(YY_START == String) YY_FTN_REJECT; // ignore in strings + if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT; + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } + +<*>^[Cc*].* { // normal comment + if(! yyextra->isFixedForm) YY_FTN_REJECT; + + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<*>"assignment"/{BS}"("{BS}"="{BS}")" { + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } +<*>"operator"/{BS}"("[^)]*")" { + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + } + + /*------ preprocessor --------------------------------------------*/ +<Start>"#".*\n { + if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT; + yyextra->contLineNr++; + startFontClass(yyscanner,"preprocessor"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + YY_FTN_RESET + } + /*------ variable references? -------------------------------------*/ + +<Start>"%"{BS}{ID} { // ignore references to elements + yyextra->code->codify(yytext); + } +<Start>{ID} { + yyextra->insideBody=TRUE; + generateLink(yyscanner,*yyextra->code, yytext); + yyextra->insideBody=FALSE; + } + /*------ strings --------------------------------------------------*/ +<String>\n { // string with \n inside + yyextra->contLineNr++; + yyextra->str+=yytext; + startFontClass(yyscanner,"stringliteral"); + codifyLines(yyscanner,yyextra->str); + endFontClass(yyscanner); + yyextra->str = ""; + YY_FTN_RESET + } +<String>\"|\' { // string ends with next quote without previous backspace + if(yytext[0]!=yyextra->stringStartSymbol) YY_FTN_REJECT; // single vs double quote + yyextra->str+=yytext; + startFontClass(yyscanner,"stringliteral"); + codifyLines(yyscanner,yyextra->str); + endFontClass(yyscanner); + yy_pop_state(yyscanner); + } +<String>. {yyextra->str+=yytext;} + +<*>\"|\' { /* string starts */ + /* if(YY_START == StrIgnore) YY_FTN_REJECT; // ignore in simple comments */ + if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT; + yy_push_state(YY_START,yyscanner); + yyextra->stringStartSymbol=yytext[0]; // single or double quote + BEGIN(String); + yyextra->str=yytext; + } + /*-----------------------------------------------------------------------------*/ + +<*>\n { + if (yyextra->endComment) + { + yyextra->endComment=FALSE; + } + else + { + codifyLines(yyscanner,yytext); + // comment cannot extend over the end of a line so should always be terminated at the end of the line. + if (yyextra->currentFontClass && !strcmp(yyextra->currentFontClass,"comment")) endFontClass(yyscanner); + } + yyextra->contLineNr++; + YY_FTN_RESET + } +<*>^{BS}"type"{BS}"=" { yyextra->code->codify(yytext); } + +<*>[\x80-\xFF]* { // keep utf8 characters together... + if (yyextra->isFixedForm && yy_my_start > fixedCommentAfter) + { + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yytext); + } + else + { + yyextra->code->codify(yytext); + } + } +<*>. { + if (yyextra->isFixedForm && yy_my_start > fixedCommentAfter) + { + //yy_push_state(YY_START,yyscanner); + //BEGIN(DocBlock); + //yyextra->docBlock=yytext; + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yytext); + } + else + { + yyextra->code->codify(yytext); + } + } +<*>{LOG_OPER} { // Fortran logical comparison keywords + yyextra->code->codify(yytext); + } +<*><<EOF>> { + if (YY_START == DocBlock) { + if (!Config_getBool(STRIP_CODE_COMMENTS)) + { + startFontClass(yyscanner,"comment"); + codifyLines(yyscanner,yyextra->docBlock); + endFontClass(yyscanner); + } + } + yyterminate(); + } +%% + +/*@ ---------------------------------------------------------------------------- + */ + +static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size) { - if (g_currentFontClass) + 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) { - g_code->endFontClass(); - g_currentFontClass=0; + *buf++ = *s++; + c++; } + yyextra->inputPosition += c; + return c; } -static void startFontClass(const char *s) +static void endFontClass(yyscan_t yyscanner) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + if (yyextra->currentFontClass) + { + yyextra->code->endFontClass(); + yyextra->currentFontClass=0; + } +} + +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 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); } } -/*! 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_sourceFileDef) + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + if (yyextra->sourceFileDef) { //QCString lineNumber,lineAnchor; - //lineNumber.sprintf("%05d",g_yyLineNr); - //lineAnchor.sprintf("l%05d",g_yyLineNr); + //lineNumber.sprintf("%05d",yyextra->yyLineNr); + //lineAnchor.sprintf("l%05d",yyextra->yyLineNr); - Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr); - //printf("startCodeLine %d d=%s\n", g_yyLineNr,d ? d->name().data() : "<null>"); - if (!g_includeCodeFragment && d) + Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr); + //printf("startCodeLine %d d=%s\n", yyextra->yyLineNr,d ? d->name().data() : "<null>"); + if (!yyextra->includeCodeFragment && d) { - g_currentDefinition = d; - g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr); - g_insideBody = FALSE; - g_endComment = FALSE; - g_parmType.resize(0); - g_parmName.resize(0); + yyextra->currentDefinition = d; + yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr); + yyextra->insideBody = FALSE; + yyextra->endComment = FALSE; 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 if (d->isLinkableInProject()) { - 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->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 endCodeLine() +static void endCodeLine(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + endFontClass(yyscanner); + yyextra->code->endCodeLine(); +} + +static void nextCodeLine(yyscan_t yyscanner) { - endFontClass(); - g_code->endCodeLine(); + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + const char * fc = yyextra->currentFontClass; + endCodeLine(yyscanner); + if (yyextra->yyLineNr<yyextra->inputLines) + { + yyextra->currentFontClass = fc; + startCodeLine(yyscanner); + } } /*! write a code fragment 'text' that may span multiple lines, inserting * line numbers for each line. */ -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_yyLineNr<g_inputLines) - { - startCodeLine(); - } - if (tmp_currentFontClass) - { - startFontClass(tmp_currentFontClass); - } + yyextra->yyLineNr++; + 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(QCString str) -{ - char *tmp= (char *) malloc(str.length()+1); - strcpy(tmp, str); - codifyLines(tmp); - free(tmp); -} - /*! 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 * 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, Definition *d,const char *text) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS); TooltipManager::instance()->addTooltip(d); QCString ref = d->getReference(); @@ -351,15 +1030,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); - endCodeLine(); - if (g_yyLineNr<g_inputLines) - { - startCodeLine(); - } + nextCodeLine(yyscanner); } else { @@ -396,7 +1071,7 @@ static bool getFortranNamespaceDefs(const QCString &mname, @returns true, if type is found */ static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName, - ClassDef *&cd, UseSDict *usedict=0) + ClassDef *&cd, UseSDict *usedict) { if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */ @@ -420,7 +1095,7 @@ static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName { if ((cd= Doxygen::classSDict->find(use->module+"::"+tname))) { - //cout << "=== type found in used module" << endl; + //cout << "=== type found in used module" << endl; return TRUE; } } @@ -436,13 +1111,14 @@ static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName @param usedict array of data of USE-statement @returns MemberDef pointer, if found, or nullptr otherwise */ -static MemberDef *getFortranDefs(const QCString &memberName, const QCString &moduleName, - UseSDict *usedict=0) +static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName, + UseSDict *usedict) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (memberName.isEmpty()) return nullptr; /* empty name => nothing to link */ // look in local variables - QListIterator<Scope> it(scopeStack); + QListIterator<Scope> it(yyextra->scopeStack); Scope *scope; for (it.toLast();(scope=it.current());--it) { @@ -524,9 +1200,9 @@ static MemberDef *getFortranDefs(const QCString &memberName, const QCString &mod gets the link to a generic procedure which depends not on the name, but on the parameter list @todo implementation */ -static bool getGenericProcedureLink(const ClassDef *cd, +static bool getGenericProcedureLink(yyscan_t yyscanner,const ClassDef *cd, const char *memberText, - CodeOutputInterface &ol) + CodeOutputInterface &ol) { (void)cd; (void)memberText; @@ -534,31 +1210,32 @@ static bool getGenericProcedureLink(const ClassDef *cd, return FALSE; } -static bool getLink(UseSDict *usedict, // dictionary with used modules +static bool getLink(yyscan_t yyscanner,UseSDict *usedict, // dictionary with used modules const char *memberText, // exact member text - CodeOutputInterface &ol, - const char *text) + CodeOutputInterface &ol, + const char *text) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; MemberDef *md=0; QCString memberName= removeRedundantWhiteSpace(memberText); - if ((md=getFortranDefs(memberName, currentModule, usedict)) && md->isLinkable()) + if ((md=getFortranDefs(yyscanner,memberName, yyextra->currentModule, usedict)) && md->isLinkable()) { if (md->isVariable() && (md->getLanguage()!=SrcLangExt_Fortran)) return FALSE; // Non Fortran variables aren't handled yet, // see also linkifyText in util.cpp const Definition *d = md->getOuterScope()==Doxygen::globalScope ? - md->getBodyDef() : md->getOuterScope(); + md->getBodyDef() : md->getOuterScope(); if (md->getGroupDef()) d = md->getGroupDef(); if (d && d->isLinkable()) { - if (g_currentDefinition && g_currentMemberDef && - md!=g_currentMemberDef && g_insideBody && g_collectXRefs) + if (yyextra->currentDefinition && yyextra->currentMemberDef && + md!=yyextra->currentMemberDef && yyextra->insideBody && yyextra->collectXRefs) { - addDocCrossReference(g_currentMemberDef,md); + addDocCrossReference(yyextra->currentMemberDef,md); } - writeMultiLineCodeLink(ol,md,text ? text : memberText); - addToSearchIndex(text ? text : memberText); + writeMultiLineCodeLink(yyscanner,ol,md,text ? text : memberText); + addToSearchIndex(yyscanner, text ? text : memberText); return TRUE; } } @@ -566,35 +1243,36 @@ static bool getLink(UseSDict *usedict, // dictionary with used modules } -static void generateLink(CodeOutputInterface &ol, char *lname) +static void generateLink(yyscan_t yyscanner,CodeOutputInterface &ol, char *lname) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; ClassDef *cd=0; NamespaceDef *nsd=0; QCString tmp = lname; tmp = removeRedundantWhiteSpace(tmp.lower()); // check if lowercase lname is a linkable type or interface - if ( (getFortranTypeDefs(tmp, currentModule, cd, useMembers)) && cd->isLinkable() ) + if ( (getFortranTypeDefs(tmp, yyextra->currentModule, cd, yyextra->useMembers)) && cd->isLinkable() ) { if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) && - (getGenericProcedureLink(cd, tmp, ol)) ) + (getGenericProcedureLink(yyscanner, cd, tmp, ol)) ) { //cout << "=== generic procedure resolved" << endl; } else { // write type or interface link - writeMultiLineCodeLink(ol,cd,tmp); - addToSearchIndex(tmp.data()); + writeMultiLineCodeLink(yyscanner, ol,cd,tmp); + addToSearchIndex(yyscanner, tmp); } } // check for module else if ( (getFortranNamespaceDefs(tmp, nsd)) && nsd->isLinkable() ) { // write module link - writeMultiLineCodeLink(ol,nsd,tmp); - addToSearchIndex(tmp.data()); + writeMultiLineCodeLink(yyscanner,ol,nsd,tmp); + addToSearchIndex(yyscanner,tmp); } // check for function/variable - else if (getLink(useMembers, tmp, ol, tmp)) + else if (getLink(yyscanner,yyextra->useMembers, tmp, ol, tmp)) { //cout << "=== found link for lowercase " << lname << endl; } @@ -602,16 +1280,17 @@ static void generateLink(CodeOutputInterface &ol, char *lname) { // nothing found, just write out the word //startFontClass("charliteral"); //test - codifyLines(tmp); - //endFontClass(); //test - addToSearchIndex(tmp.data()); + codifyLines(yyscanner,tmp); + //endFontClass(yyscanner); //test + addToSearchIndex(yyscanner,tmp); } } /*! 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)) @@ -619,712 +1298,69 @@ static int countLines() 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; + yyextra->needsTermination=TRUE; } return count; } //---------------------------------------------------------------------------- /** start scope */ -static void startScope() +static void startScope(yyscan_t yyscanner) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; DBG_CTX((stderr, "===> startScope %s",yytext)); Scope *scope = new Scope; - scopeStack.append(scope); + yyextra->scopeStack.append(scope); } /** end scope */ -static void endScope() +static void endScope(yyscan_t yyscanner) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; DBG_CTX((stderr,"===> endScope %s",yytext)); - if (scopeStack.isEmpty()) + if (yyextra->scopeStack.isEmpty()) { DBG_CTX((stderr,"WARNING: fortrancode.l: stack empty!\n")); return; } - Scope *scope = scopeStack.getLast(); - scopeStack.removeLast(); + Scope *scope = yyextra->scopeStack.getLast(); + yyextra->scopeStack.removeLast(); for ( QCStringList::Iterator it = scope->useNames.begin(); it != scope->useNames.end(); ++it) { - useMembers->remove(*it); + yyextra->useMembers->remove(*it); } delete scope; } -static void addUse(const QCString &moduleName) +static void addUse(yyscan_t yyscanner,const QCString &moduleName) { - if (!scopeStack.isEmpty()) - scopeStack.getLast()->useNames.append(moduleName); + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + if (!yyextra->scopeStack.isEmpty()) + yyextra->scopeStack.getLast()->useNames.append(moduleName); } -static void addLocalVar(const QCString &varName) +static void addLocalVar(yyscan_t yyscanner,const QCString &varName) { - if (!scopeStack.isEmpty()) + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + if (!yyextra->scopeStack.isEmpty()) { std::string lowVarName = varName.lower().str(); - scopeStack.getLast()->localVars.insert(lowVarName); - if (g_isExternal) scopeStack.getLast()->externalVars.insert(lowVarName); - } -} - -//---------------------------------------------------------------------------- - -/* -----------------------------------------------------------------*/ -#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++; + yyextra->scopeStack.getLast()->localVars.insert(lowVarName); + if (yyextra->isExternal) yyextra->scopeStack.getLast()->externalVars.insert(lowVarName); } - return c; } -%} - -IDSYM [a-z_A-Z0-9] -ID [a-z_A-Z]+{IDSYM}* -SUBPROG (subroutine|function) -B [ \t] -BS [ \t]* -BS_ [ \t]+ -COMMA {BS},{BS} -ARGS_L0 ("("[^)]*")") -ARGS_L1a [^()]*"("[^)]*")"[^)]* -ARGS_L1 ("("{ARGS_L1a}*")") -ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")" -ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2}) - -NUM_TYPE (complex|integer|logical|real) -LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.) -KIND {ARGS} -CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS})) -TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE|CLASS|PROCEDURE|ENUMERATOR) - -INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")" -ATTR_SPEC (IMPLICIT|ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|(NON_)?RECURSIVE|PURE|IMPURE|ELEMENTAL|VALUE|NOPASS|DEFERRED|CONTIGUOUS|VOLATILE) -ACCESS_SPEC (PROTECTED|PRIVATE|PUBLIC) -/* Assume that attribute statements are almost the same as attributes. */ -ATTR_STMT {ATTR_SPEC}|DIMENSION -FLOW (DO|SELECT|CASE|SELECT{BS}(CASE|TYPE)|WHERE|IF|THEN|ELSE|WHILE|FORALL|ELSEWHERE|ELSEIF|RETURN|CONTINUE|EXIT|GO{BS}TO) -COMMANDS (FORMAT|CONTAINS|MODULE{BS_}PROCEDURE|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|PRESENT|DEALLOCATE|NULLIFY|SIZE|INQUIRE|OPEN|CLOSE|FLUSH|DATA|COMMON) -IGNORE (CALL) -PREFIX ((NON_)?RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,4}((NON_)?RECURSIVE|IMPURE|PURE|ELEMENTAL)?0 -LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")" - -/* | */ - -%option noyywrap -%option stack -%option caseless -/*%option debug*/ - -%x Start -%x SubCall -%x FuncDef -%x ClassName -%x ClassVar -%x Subprog -%x DocBlock -%x Use -%x UseOnly -%x Import -%x Declaration -%x DeclarationBinding -%x DeclContLine -%x Parameterlist -%x String -%x Subprogend - -%% - /*==================================================================*/ - - /*-------- ignore ------------------------------------------------------------*/ - -<Start>{IGNORE}/{BS}"(" { // do not search keywords, intrinsics... TODO: complete list - codifyLines(yytext); - } - /*-------- inner construct ---------------------------------------------------*/ - -<Start>{COMMANDS}/{BS}[,( \t\n] { // highlight - /* font class is defined e.g. in doxygen.css */ - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - } -<Start>{FLOW}/{BS}[,( \t\n] { - if (g_isFixedForm) - { - if ((yy_my_start == 1) && ((yytext[0] == 'c') || (yytext[0] == 'C'))) YY_FTN_REJECT; - } - if (g_currentMemberDef && g_currentMemberDef->isFunction()) - { - g_currentMemberDef->incrementFlowKeyWordCount(); - } - /* font class is defined e.g. in doxygen.css */ - startFontClass("keywordflow"); - codifyLines(yytext); - endFontClass(); - } -<Start>{BS}(CASE|CLASS|TYPE){BS_}(IS|DEFAULT) { - startFontClass("keywordflow"); - codifyLines(yytext); - endFontClass(); - } -<Start>{BS}"end"({BS}{FLOW})/[ \t\n] { // list is a bit long as not all have possible end - startFontClass("keywordflow"); - codifyLines(yytext); - endFontClass(); - } -<Start>"implicit"{BS}("none"|{TYPE_SPEC}) { - startFontClass("keywordtype"); - codifyLines(yytext); - endFontClass(); - } -<Start>^{BS}"namelist"/[//] { // Namelist specification - startFontClass("keywordtype"); - codifyLines(yytext); - endFontClass(); - } - /*-------- use statement -------------------------------------------*/ -<Start>"use"{BS_} { - startFontClass("keywordtype"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(Use); - } -<Use>"ONLY" { // TODO: rename - startFontClass("keywordtype"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(UseOnly); - } -<Use>{ID} { - QCString tmp = yytext; - tmp = tmp.lower(); - g_insideBody=TRUE; - generateLink(*g_code, yytext); - g_insideBody=FALSE; - - /* append module name to use dict */ - useEntry = new UseEntry(); - //useEntry->module = yytext; - //useMembers->append(yytext, useEntry); - //addUse(yytext); - useEntry->module = tmp; - useMembers->append(tmp, useEntry); - addUse(tmp); - } -<Use,UseOnly,Import>{BS},{BS} { codifyLines(yytext); } -<UseOnly,Import>{BS}&{BS}"\n" { codifyLines(yytext); - g_contLineNr++; - YY_FTN_RESET} -<UseOnly>{ID} { - QCString tmp = yytext; - tmp = tmp.lower(); - useEntry->onlyNames.append(tmp); - g_insideBody=TRUE; - generateLink(*g_code, yytext); - g_insideBody=FALSE; - } -<Use,UseOnly,Import>"\n" { - unput(*yytext); - yy_pop_state();YY_FTN_RESET - } -<*>"import"{BS}/"\n" | -<*>"import"{BS_} { - startFontClass("keywordtype"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(Import); - } -<Import>{ID} { - g_insideBody=TRUE; - generateLink(*g_code, yytext); - g_insideBody=FALSE; - } -<Import>("ONLY"|"NONE"|"ALL") { - startFontClass("keywordtype"); - codifyLines(yytext); - endFontClass(); - } - /*-------- fortran module -----------------------------------------*/ -<Start>("block"{BS}"data"|"program"|"module"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { // - startScope(); - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(ClassName); - if (!qstricmp(yytext,"module")) currentModule="module"; - } -<Start>("enum")/{BS_}|{BS}{COMMA}{BS}{LANGUAGE_BIND_SPEC}|\n { // - startScope(); - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(ClassName); - currentClass="class"; - } -<*>{LANGUAGE_BIND_SPEC} { // - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - } -<Start>("type")/{BS_}|({COMMA}({ACCESS_SPEC}|ABSTRACT|EXTENDS))|\n { // - startScope(); - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(ClassName); - currentClass="class"; - } -<ClassName>{ID} { - if (currentModule == "module") - { - currentModule=yytext; - currentModule = currentModule.lower(); - } - generateLink(*g_code,yytext); - yy_pop_state(); - } -<ClassName>({ACCESS_SPEC}|ABSTRACT|EXTENDS)/[,:( ] { //| variable declaration - startFontClass("keyword"); - g_code->codify(yytext); - endFontClass(); - } -<ClassName>\n { // interface may be without name - yy_pop_state(); - YY_FTN_REJECT; - } -<Start>^{BS}"end"({BS_}"enum").* { // just reset currentClass, rest is done in following rule - currentClass=0; - YY_FTN_REJECT; - } -<Start>^{BS}"end"({BS_}"type").* { // just reset currentClass, rest is done in following rule - currentClass=0; - YY_FTN_REJECT; - } -<Start>^{BS}"end"({BS_}"module").* { // just reset currentModule, rest is done in following rule - currentModule=0; - YY_FTN_REJECT; - } - /*-------- subprog definition -------------------------------------*/ -<Start>({PREFIX}{BS_})?{TYPE_SPEC}{BS_}({PREFIX}{BS_})?{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - } -<Start>({PREFIX}{BS_})?{SUBPROG}{BS_} { // Fortran subroutine or function found - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(Subprog); - } -<Subprog>{ID} { // subroutine/function name - DBG_CTX((stderr, "===> start subprogram %s\n", yytext)); - startScope(); - generateLink(*g_code,yytext); - } -<Subprog>"result"/{BS}"("[^)]*")" { - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - } -<Subprog>"("[^)]*")" { // ignore rest of line - codifyLines(yytext); - } -<Subprog,Subprogend>"\n" { codifyLines(yytext); - g_contLineNr++; - yy_pop_state(); - YY_FTN_RESET - } -<Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface")?{BS} { // Fortran subroutine or function ends - //cout << "===> end function " << yytext << endl; - endScope(); - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(Subprogend); - } -<Subprogend>{ID}/{BS}(\n|!|;) { - generateLink(*g_code,yytext); - yy_pop_state(); - } -<Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface"){BS}/(\n|!|;) { // Fortran subroutine or function ends - //cout << "===> end function " << yytext << endl; - endScope(); - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - } - /*-------- variable declaration ----------------------------------*/ -<Start>^{BS}"real"/[,:( ] { // real is a bit tricky as it is a data type but also a function. - yy_push_state(YY_START); - BEGIN(Declaration); - startFontClass("keywordtype"); - g_code->codify(yytext); - endFontClass(); - } -<Start>{TYPE_SPEC}/[,:( ] { - QCString typ = yytext; - typ = removeRedundantWhiteSpace(typ.lower()); - if (typ.startsWith("real")) YY_FTN_REJECT; - if (typ == "type" || typ == "class" || typ == "procedure") inTypeDecl = 1; - yy_push_state(YY_START); - BEGIN(Declaration); - startFontClass("keywordtype"); - g_code->codify(yytext); - endFontClass(); - } -<Start>{ATTR_SPEC} { - if (QCString(yytext) == "external") - { - yy_push_state(YY_START); - BEGIN(Declaration); - g_isExternal = true; - } - startFontClass("keywordtype"); - g_code->codify(yytext); - endFontClass(); - } -<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable declaration - if (QCString(yytext) == "external") g_isExternal = true; - startFontClass("keywordtype"); - g_code->codify(yytext); - endFontClass(); - } -<Declaration>{ID} { // local var - if (g_isFixedForm && yy_my_start == 1) - { - startFontClass("comment"); - g_code->codify(yytext); - endFontClass(); - } - else if (g_currentMemberDef && - ((g_currentMemberDef->isFunction() && (g_currentMemberDef->typeString()!=QCString("subroutine") || inTypeDecl)) || - g_currentMemberDef->isVariable() || g_currentMemberDef->isEnumValue() - ) - ) - { - generateLink(*g_code, yytext); - } - else - { - g_code->codify(yytext); - addLocalVar(yytext); - } - } -<Declaration>{BS}("=>"|"="){BS} { // Procedure binding - BEGIN(DeclarationBinding); - g_code->codify(yytext); - } -<DeclarationBinding>{ID} { // Type bound procedure link - generateLink(*g_code, yytext); - yy_pop_state(); - } -<Declaration>[(] { // start of array or type / class specification - bracketCount++; - g_code->codify(yytext); - } - -<Declaration>[)] { // end array specification - bracketCount--; - if (!bracketCount) inTypeDecl = 0; - g_code->codify(yytext); - } - -<Declaration,DeclarationBinding>"&" { // continuation line - g_code->codify(yytext); - if (!g_isFixedForm) - { - yy_push_state(YY_START); - BEGIN(DeclContLine); - } - } -<DeclContLine>"\n" { // declaration not yet finished - g_contLineNr++; - codifyLines(yytext); - bracketCount = 0; - yy_pop_state(); - YY_FTN_RESET - } -<Declaration,DeclarationBinding>"\n" { // end declaration line (?) - if (g_endComment) - { - g_endComment=FALSE; - } - else - { - codifyLines(yytext); - } - bracketCount = 0; - g_contLineNr++; - if (!(g_hasContLine && g_hasContLine[g_contLineNr - 1])) - { - g_isExternal = false; - yy_pop_state(); - } - YY_FTN_RESET - } - - /*-------- subprog calls -----------------------------------------*/ - -<Start>"call"{BS_} { - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - yy_push_state(YY_START); - BEGIN(SubCall); - } -<SubCall>{ID} { // subroutine call - g_insideBody=TRUE; - generateLink(*g_code, yytext); - g_insideBody=FALSE; - yy_pop_state(); - } -<Start>{ID}{BS}/"(" { // function call - if (g_isFixedForm && yy_my_start == 6) - { - // fixed form continuation line - YY_FTN_REJECT; - } - else if (QCString(yytext).stripWhiteSpace().lower() == "type") - { - yy_push_state(YY_START); - BEGIN(Declaration); - startFontClass("keywordtype"); - g_code->codify(QCString(yytext).stripWhiteSpace()); - endFontClass(); - g_code->codify(yytext + 4); - } - else - { - g_insideBody=TRUE; - generateLink(*g_code, yytext); - g_insideBody=FALSE; - } - } - - /*-------- comments ---------------------------------------------------*/ -<Start,Declaration,DeclarationBinding>\n?{BS}"!>"|"!<" { // start comment line or comment block - if (yytext[0] == '\n') - { - g_contLineNr++; - yy_old_start = 0; - yy_my_start = 1; - yy_end = static_cast<int>(yyleng); - } - // Actually we should see if ! on position 6, can be continuation - // but the chance is very unlikely, so no effort to solve it here - yy_push_state(YY_START); - BEGIN(DocBlock); - docBlock=yytext; - } -<Declaration,DeclarationBinding>{BS}"!<" { // start comment line or comment block - yy_push_state(YY_START); - BEGIN(DocBlock); - docBlock=yytext; - } - -<DocBlock>.* { // contents of current comment line - docBlock+=yytext; - } -<DocBlock>"\n"{BS}("!>"|"!<"|"!!") { // comment block (next line is also comment line) - g_contLineNr++; - yy_old_start = 0; - yy_my_start = 1; - yy_end = static_cast<int>(yyleng); - // Actually we should see if ! on position 6, can be continuation - // but the chance is very unlikely, so no effort to solve it here - docBlock+=yytext; - } -<DocBlock>"\n" { // comment block ends at the end of this line - // remove special comment (default config) - g_contLineNr++; - if (Config_getBool(STRIP_CODE_COMMENTS)) - { - g_yyLineNr+=((QCString)docBlock).contains('\n'); - g_yyLineNr+=1; - endCodeLine(); - if (g_yyLineNr<g_inputLines) - { - startCodeLine(); - } - g_endComment=TRUE; - } - else // do not remove comment - { - startFontClass("comment"); - codifyLines(docBlock); - endFontClass(); - } - unput(*yytext); - g_contLineNr--; - yy_pop_state(); - YY_FTN_RESET - } - -<*>"!"[^><\n].*|"!"$ { // normal comment - if(YY_START == String) YY_FTN_REJECT; // ignore in strings - if (g_isFixedForm && yy_my_start == 6) YY_FTN_REJECT; - startFontClass("comment"); - codifyLines(yytext); - endFontClass(); - } - -<*>^[Cc*].* { // normal comment - if(! g_isFixedForm) YY_FTN_REJECT; - - startFontClass("comment"); - codifyLines(yytext); - endFontClass(); - } -<*>"assignment"/{BS}"("{BS}"="{BS}")" { - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - } -<*>"operator"/{BS}"("[^)]*")" { - startFontClass("keyword"); - codifyLines(yytext); - endFontClass(); - } - - /*------ preprocessor --------------------------------------------*/ -<Start>"#".*\n { - if (g_isFixedForm && yy_my_start == 6) YY_FTN_REJECT; - g_contLineNr++; - startFontClass("preprocessor"); - codifyLines(yytext); - endFontClass(); - YY_FTN_RESET - } - /*------ variable references? -------------------------------------*/ - -<Start>"%"{BS}{ID} { // ignore references to elements - g_code->codify(yytext); - } -<Start>{ID} { - g_insideBody=TRUE; - generateLink(*g_code, yytext); - g_insideBody=FALSE; - } - /*------ strings --------------------------------------------------*/ -<String>\n { // string with \n inside - g_contLineNr++; - g_str+=yytext; - startFontClass("stringliteral"); - codifyLines(g_str); - endFontClass(); - g_str = ""; - YY_FTN_RESET - } -<String>\"|\' { // string ends with next quote without previous backspace - if(yytext[0]!=stringStartSymbol) YY_FTN_REJECT; // single vs double quote - g_str+=yytext; - startFontClass("stringliteral"); - codifyLines(g_str); - endFontClass(); - yy_pop_state(); - } -<String>. {g_str+=yytext;} - -<*>\"|\' { /* string starts */ - /* if(YY_START == StrIgnore) YY_FTN_REJECT; // ignore in simple comments */ - if (g_isFixedForm && yy_my_start == 6) YY_FTN_REJECT; - yy_push_state(YY_START); - stringStartSymbol=yytext[0]; // single or double quote - BEGIN(String); - g_str=yytext; - } - /*-----------------------------------------------------------------------------*/ - -<*>\n { - if (g_endComment) - { - g_endComment=FALSE; - } - else - { - codifyLines(yytext); - // comment cannot extend over the end of a line so should always be terminated at the end of the line. - if (g_currentFontClass && !strcmp(g_currentFontClass,"comment")) endFontClass(); - } - g_contLineNr++; - YY_FTN_RESET - } -<*>^{BS}"type"{BS}"=" { g_code->codify(yytext); } - -<*>[\x80-\xFF]* { // keep utf8 characters together... - if (g_isFixedForm && yy_my_start > fixedCommentAfter) - { - startFontClass("comment"); - codifyLines(yytext); - } - else - { - g_code->codify(yytext); - } - } -<*>. { - if (g_isFixedForm && yy_my_start > fixedCommentAfter) - { - //yy_push_state(YY_START); - //BEGIN(DocBlock); - //docBlock=yytext; - startFontClass("comment"); - codifyLines(yytext); - } - else - { - g_code->codify(yytext); - } - } -<*>{LOG_OPER} { // Fortran logical comparison keywords - g_code->codify(yytext); - } -<*><<EOF>> { - if (YY_START == DocBlock) { - if (!Config_getBool(STRIP_CODE_COMMENTS)) - { - startFontClass("comment"); - codifyLines(docBlock); - endFontClass(); - } - } - yyterminate(); - } -%% - -/*@ ---------------------------------------------------------------------------- - */ - /*===================================================================*/ -void resetFortranCodeParserState() {} - -bool recognizeFixedForm(const char* contents, FortranFormat format); /* prototype, implementation in fortranscanner.l */ -const char* prepassFixedForm(const char* contents, int *hasContLine); /* prototype, implementation in fortranscanner.l */ -static void checkContLines(const char *s) +static void checkContLines(yyscan_t yyscanner,const char *s) { + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; int numLines = 0; int i = 0; const char *p = s; @@ -1336,91 +1372,58 @@ static void checkContLines(const char *s) p++; } - g_hasContLine = (int *) malloc((numLines) * sizeof(int)); + yyextra->hasContLine = (int *) malloc((numLines) * sizeof(int)); for (i = 0; i < numLines; i++) - g_hasContLine[i] = 0; - p = prepassFixedForm(s, g_hasContLine); - g_hasContLine[0] = 0; + yyextra->hasContLine[i] = 0; + p = prepassFixedForm(s, yyextra->hasContLine); + yyextra->hasContLine[0] = 0; } void parseFortranCode(CodeOutputInterface &od,const char *,const QCString &s, bool exBlock, const char *exName,FileDef *fd, - int startLine,int endLine,bool inlineFragment, - const MemberDef *,bool,const Definition *searchCtx, + int startLine,int endLine,bool inlineFragment, + const MemberDef *,bool,const Definition *searchCtx, bool collectXRefs, FortranFormat format) { //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd); - 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_isFixedForm = recognizeFixedForm((const char*)s,format); - g_contLineNr = 1; - g_hasContLine = NULL; - if (g_isFixedForm) - { - checkContLines(g_inputString); - } - g_currentFontClass = 0; - g_needsTermination = FALSE; - g_searchCtx = searchCtx; - g_collectXRefs = collectXRefs; - if (startLine!=-1) - g_yyLineNr = startLine; - else - g_yyLineNr = 1; - - if (endLine!=-1) - g_inputLines = endLine+1; - else - g_inputLines = g_yyLineNr + countLines() - 1; - - g_exampleBlock = exBlock; - g_exampleName = exName; - g_sourceFileDef = fd; - if (exBlock && fd==0) - { - // create a dummy filedef for the example - g_sourceFileDef = createFileDef("",exName); - } - if (g_sourceFileDef) - { - setCurrentDoc("l00001"); - } - g_currentDefinition = 0; - g_currentMemberDef = 0; - if (!g_exampleName.isEmpty()) - { - g_exampleFile = convertNameToFile(g_exampleName+"-example"); - } - g_includeCodeFragment = inlineFragment; - startCodeLine(); - g_parmName.resize(0); - g_parmType.resize(0); - fortrancodeYYrestart( fortrancodeYYin ); - BEGIN( Start ); - fortrancodeYYlex(); - if (g_needsTermination) - { - endFontClass(); - g_code->endCodeLine(); - } - if (exBlock && g_sourceFileDef) - { - // delete the temporary file definition used for this example - delete g_sourceFileDef; - g_sourceFileDef=0; - } - if (g_hasContLine) free(g_hasContLine); - g_hasContLine = NULL; - printlex(yy_flex_debug, FALSE, __FILE__, fd ? fd->fileName().data(): NULL); return; } //--------------------------------------------------------- +struct FortranCodeParser::Private +{ + yyscan_t yyscanner; + fortrancodeYY_state state; + FortranFormat format; +}; + +FortranCodeParser::FortranCodeParser(FortranFormat format) : p(std::make_unique<Private>()) +{ + p->format = format; + fortrancodeYYlex_init_extra(&p->state,&p->yyscanner); +#ifdef FLEX_DEBUG + fortrancodeYYset_debug(1,p->yyscanner); +#endif + resetCodeParserState(); +} + +FortranCodeParser::~FortranCodeParser() +{ + fortrancodeYYlex_destroy(p->yyscanner); +} + +void FortranCodeParser::resetCodeParserState() +{ + struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; + yyextra->currentDefinition = 0; + yyextra->currentMemberDef = 0; + yyextra->currentFontClass = 0; + yyextra->needsTermination = FALSE; + BEGIN( Start ); +} + void FortranCodeParser::parseCode(CodeOutputInterface & codeOutIntf, const char * scopeName, const QCString & input, @@ -1431,20 +1434,85 @@ void FortranCodeParser::parseCode(CodeOutputInterface & codeOutIntf, int startLine, int endLine, bool inlineFragment, - const MemberDef *memberDef, + const MemberDef *memberDef, bool showLineNumbers, const Definition *searchCtx, bool collectXRefs ) { - ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, - fileDef,startLine,endLine,inlineFragment,memberDef, - showLineNumbers,searchCtx,collectXRefs,m_format); -} + yyscan_t yyscanner = p->yyscanner; + struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; + //::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, + // fileDef,startLine,endLine,inlineFragment,memberDef, + // showLineNumbers,searchCtx,collectXRefs,m_format); + // parseFortranCode(CodeOutputInterface &od,const char *,const QCString &s, + // bool exBlock, const char *exName,FileDef *fd, + // int startLine,int endLine,bool inlineFragment, + // const MemberDef *,bool,const Definition *searchCtx, + // bool collectXRefs, FortranFormat format) + 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->isFixedForm = recognizeFixedForm(input,p->format); + yyextra->contLineNr = 1; + yyextra->hasContLine = NULL; + if (yyextra->isFixedForm) + { + checkContLines(yyscanner,yyextra->inputString); + } + yyextra->currentFontClass = 0; + yyextra->needsTermination = FALSE; + yyextra->searchCtx = searchCtx; + yyextra->collectXRefs = collectXRefs; + if (startLine!=-1) + yyextra->yyLineNr = startLine; + else + yyextra->yyLineNr = 1; -void FortranCodeParser::resetCodeParserState() -{ - ::resetFortranCodeParserState(); + if (endLine!=-1) + yyextra->inputLines = endLine+1; + else + yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1; + + yyextra->exampleBlock = isExampleBlock; + yyextra->exampleName = exampleName; + yyextra->sourceFileDef = fileDef; + if (isExampleBlock && fileDef==0) + { + // create a dummy filedef for the example + yyextra->sourceFileDef = createFileDef("",exampleName); + } + if (yyextra->sourceFileDef) + { + setCurrentDoc(yyscanner,"l00001"); + } + yyextra->currentDefinition = 0; + yyextra->currentMemberDef = 0; + if (!yyextra->exampleName.isEmpty()) + { + yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example"); + } + yyextra->includeCodeFragment = inlineFragment; + startCodeLine(yyscanner); + fortrancodeYYrestart(0, yyscanner); + BEGIN( Start ); + fortrancodeYYlex(yyscanner); + if (yyextra->needsTermination) + { + endFontClass(yyscanner); + yyextra->code->endCodeLine(); + } + if (isExampleBlock && yyextra->sourceFileDef) + { + // delete the temporary file definition used for this example + delete yyextra->sourceFileDef; + yyextra->sourceFileDef=0; + } + if (yyextra->hasContLine) free(yyextra->hasContLine); + yyextra->hasContLine = NULL; + printlex(yy_flex_debug, FALSE, __FILE__, fileDef ? fileDef->fileName().data(): NULL); } //--------------------------------------------------------- diff --git a/src/fortranscanner.h b/src/fortranscanner.h index 0e67bb2..3133820 100644 --- a/src/fortranscanner.h +++ b/src/fortranscanner.h @@ -53,5 +53,9 @@ class FortranOutlineParserFixed : public FortranOutlineParser FortranOutlineParserFixed() : FortranOutlineParser(FortranFormat_Fixed) { } }; +bool recognizeFixedForm(const char* contents, FortranFormat format); + +const char* prepassFixedForm(const char* contents, int *hasContLine); + #endif diff --git a/src/fortranscanner.l b/src/fortranscanner.l index cf48a3e..ed41d81 100644 --- a/src/fortranscanner.l +++ b/src/fortranscanner.l @@ -2687,6 +2687,9 @@ static void parseMain(yyscan_t yyscanner, const char *fileName,const char *fileB char *tmpBuf = NULL; initParser(yyscanner); + + if (fileBuf==0 || fileBuf[0]=='\0') return; + yyextra->defaultProtection = Public; yyextra->inputString = fileBuf; yyextra->inputPosition = 0; |