Doxygen
Loading...
Searching...
No Matches
fortranscanner.l File Reference
#include <stdint.h>
#include "fortranscanner.h"
#include <algorithm>
#include <map>
#include <memory>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "arguments.h"
#include "commentscan.h"
#include "config.h"
#include "debug.h"
#include "doxygen.h"
#include "entry.h"
#include "markdown.h"
#include "message.h"
#include "util.h"
#include "doxygen_lex.h"
#include "fortranscanner.l.h"
Include dependency graph for fortranscanner.l:

Go to the source code of this file.

Classes

struct  BlockState
struct  SymbolModifiers
 Holds yyextra->modifiers (ie attributes) for one symbol (variable, function, etc). More...
struct  CommentInPrepass
struct  fortranscannerYY_state
struct  FortranOutlineParser::Private

Macros

#define YY_TYPEDEF_YY_SCANNER_T
#define DBG_CTX(x)
#define YY_NO_INPUT   1
#define YY_NO_UNISTD_H   1
#define YY_INPUT(buf, result, max_size)
#define YY_USER_ACTION   yyextra->colNr+=(int)yyleng;
#define INVALID_ENTRY   ((Entry*)0x8)

Typedefs

typedef yyguts_t * yyscan_t

Enumerations

enum  ScanVar { V_IGNORE , V_VARIABLE , V_PARAMETER , V_RESULT }
enum  InterfaceType { IF_NONE , IF_SPECIFIC , IF_GENERIC , IF_ABSTRACT }

Functions

static int getAmpersandAtTheStart (const char *buf, int length)
static int getAmpOrExclAtTheEnd (const char *buf, int length, char ch)
static DString extractFromParens (const DString &name)
static DString extractBind (const DString &name)
static int yyread (yyscan_t yyscanner, char *buf, int max_size)
static void startCommentBlock (yyscan_t yyscanner, bool)
static void handleCommentBlock (yyscan_t yyscanner, const DString &doc, bool brief)
static void subrHandleCommentBlock (yyscan_t yyscanner, const DString &doc, bool brief)
 Handle parameter description as defined after the declaration of the parameter.
static void subrHandleCommentBlockResult (yyscan_t yyscanner, const DString &doc, bool brief)
 Handle result description as defined after the declaration of the parameter.
static void addCurrentEntry (yyscan_t yyscanner, bool case_insens)
 adds yyextra->current entry to yyextra->current_root and creates new yyextra->current
static void addModule (yyscan_t yyscanner, const DString &name=DString(), bool isModule=false)
static void addSubprogram (yyscan_t yyscanner, const DString &text)
static void addInterface (yyscan_t yyscanner, DString name, InterfaceType type)
static ArgumentgetParameter (yyscan_t yyscanner, const DString &name)
static void scanner_abort (yyscan_t yyscanner)
static void pop_state (yyscan_t yyscanner)
static void pushBlockState (yyscan_t yyscanner, const DString &text)
static void popBlockState (yyscan_t yyscanner)
static void startScope (yyscan_t yyscanner, Entry *scope)
static bool endScope (yyscan_t yyscanner, Entry *scope, bool isGlobalRoot=false)
static void copyEntry (std::shared_ptr< Entry > dest, const std::shared_ptr< Entry > &src)
 used to copy entry to an interface module procedure
static void resolveModuleProcedures (yyscan_t yyscanner, Entry *current_root)
 fill empty interface module procedures with info from corresponding module subprogs
static void resolveTypeBoundProcedures (Entry *scope)
static void truncatePrepass (yyscan_t yyscanner, int index)
static void pushBuffer (yyscan_t yyscanner, const DString &buffer)
static void popBuffer (yyscan_t yyscanner)
static const CommentInPrepasslocatePrepassComment (yyscan_t yyscanner, int from, int to)
static void updateVariablePrepassComment (yyscan_t yyscanner, int from, int to)
static void newLine (yyscan_t yyscanner)
static void initEntry (yyscan_t yyscanner)
static const char * stateToString (int state)
static int computeIndent (const char *s)
static const char * getLexerFILE ()
int yylex (yyscan_t yyscanner)
 fortran parsing states
static void insertCharacter (char *contents, int length, int pos, char c)
const char * prepassFixedForm (const char *contents, int *hasContLine, int fixedCommentAfter)
static bool keyWordsFortranC (const char *contents)
bool recognizeFixedForm (const DString &contents, FortranFormat format)
FortranFormat convertFileNameFortranParserCode (const DString &fn)
static ArgumentfindArgument (Entry *subprog, DString name, bool byTypeName=false)
static DString applyModifiers (DString typeName, const SymbolModifiers &mdfs)
static void applyModifiers (Argument *arg, const SymbolModifiers &mdfs)
static void applyModifiers (Entry *ent, const SymbolModifiers &mdfs)
static void initParser (yyscan_t yyscanner)
static void parseMain (yyscan_t yyscanner, const DString &fileName, const char *fileBuf, const std::shared_ptr< Entry > &rt, FortranFormat format)

Variables

static const char * directionStrs []
static const char * directionParam []

Macro Definition Documentation

◆ DBG_CTX

#define DBG_CTX ( x)
Value:
do { } while(0)

Definition at line 80 of file fortranscanner.l.

Referenced by addModule(), addSubprogram(), and handleCommentBlock().

◆ INVALID_ENTRY

#define INVALID_ENTRY   ((Entry*)0x8)

Definition at line 272 of file fortranscanner.l.

Referenced by endScope(), and parseMain().

◆ YY_INPUT

#define YY_INPUT ( buf,
result,
max_size )
Value:
result=yyread(yyscanner,buf,max_size);
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition xml.l:230

Definition at line 266 of file fortranscanner.l.

◆ YY_NO_INPUT

#define YY_NO_INPUT   1

Definition at line 82 of file fortranscanner.l.

◆ YY_NO_UNISTD_H

#define YY_NO_UNISTD_H   1

Definition at line 83 of file fortranscanner.l.

◆ YY_TYPEDEF_YY_SCANNER_T

#define YY_TYPEDEF_YY_SCANNER_T

Definition at line 48 of file fortranscanner.l.

◆ YY_USER_ACTION

#define YY_USER_ACTION   yyextra->colNr+=(int)yyleng;

Definition at line 271 of file fortranscanner.l.

Typedef Documentation

◆ yyscan_t

typedef yyguts_t* yyscan_t

Definition at line 50 of file fortranscanner.l.

Enumeration Type Documentation

◆ InterfaceType

Enumerator
IF_NONE 
IF_SPECIFIC 
IF_GENERIC 
IF_ABSTRACT 

Definition at line 86 of file fortranscanner.l.

86{ IF_NONE, IF_SPECIFIC, IF_GENERIC, IF_ABSTRACT };

◆ ScanVar

enum ScanVar
Enumerator
V_IGNORE 
V_VARIABLE 
V_PARAMETER 
V_RESULT 

Definition at line 85 of file fortranscanner.l.

85{ V_IGNORE, V_VARIABLE, V_PARAMETER, V_RESULT};

Function Documentation

◆ addCurrentEntry()

void addCurrentEntry ( yyscan_t yyscanner,
bool case_insens )
static

adds yyextra->current entry to yyextra->current_root and creates new yyextra->current

Definition at line 2973 of file fortranscanner.l.

2974{
2975 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2976 if (case_insens) yyextra->current->name = yyextra->current->name.lower();
2977 //printf("===Adding entry %s to %s\n", qPrint(yyextra->current->name), qPrint(yyextra->current_root->name));
2978 yyextra->last_entry = yyextra->current;
2979 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
2980 initEntry(yyscanner);
static void initEntry(yyscan_t yyscanner)
2981}

References initEntry().

Referenced by addInterface(), addModule(), and handleCommentBlock().

◆ addInterface()

void addInterface ( yyscan_t yyscanner,
DString name,
InterfaceType type )
static

Adds interface to the root entry.

Note
Code was brought to this procedure from the parser, because there was/is idea to use it in several parts of the parser.

Definition at line 3047 of file fortranscanner.l.

3048{
3049 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3050 if (YY_START == Start)
3051 {
3052 addModule(yyscanner);
3053 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
3054 yy_push_state(ModuleBody,yyscanner); //anon program
3055 }
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
static void addModule(yyscan_t yyscanner, const DString &name=DString(), bool isModule=false)
static void pushBlockState(yyscan_t yyscanner, const DString &text)
3056
3057 yyextra->current->section = EntryType::makeClass(); // was EntryType::Interface;
3058 yyextra->current->spec = TypeSpecifier().setInterface(true);
3059 yyextra->current->name = name;
Wrapper class for a number of boolean properties.
Definition types.h:694
3060
3061 switch (type)
3062 {
3063 case IF_ABSTRACT:
3064 yyextra->current->type = "abstract";
3065 break;
@ IF_ABSTRACT
3066
3067 case IF_GENERIC:
3068 yyextra->current->type = "generic";
3069 break;
@ IF_GENERIC
3070
3071 case IF_SPECIFIC:
3072 case IF_NONE:
3073 default:
3074 yyextra->current->type = "";
3075 }
@ IF_NONE
@ IF_SPECIFIC
3076
3077 /* if type is part of a module, mod name is necessary for output */
3078 if ((yyextra->current_root) &&
3079 (yyextra->current_root->section.isClass() ||
3080 yyextra->current_root->section.isNamespace()))
3081 {
3082 yyextra->current->name= yyextra->current_root->name + "::" + yyextra->current->name;
3083 }
3084
3085 yyextra->current->fileName = yyextra->fileName;
3086 yyextra->current->bodyLine = yyextra->lineNr;
3087 yyextra->current->startLine = yyextra->lineNr;
3088 addCurrentEntry(yyscanner,true);
static void addCurrentEntry(yyscan_t yyscanner, bool case_insens)
adds yyextra->current entry to yyextra->current_root and creates new yyextra->current
3089}

References addCurrentEntry(), addModule(), IF_ABSTRACT, IF_GENERIC, IF_NONE, IF_SPECIFIC, and pushBlockState().

◆ addModule()

void addModule ( yyscan_t yyscanner,
const DString & name = DString(),
bool isModule = false )
static

Definition at line 2983 of file fortranscanner.l.

2984{
2985 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2986 DBG_CTX((stderr, "0=========> got module %s\n", qPrint(name)));
const char * qPrint(const char *s)
Definition dstring.h:783
#define DBG_CTX(x)
2987
2988 if (isModule)
2989 yyextra->current->section = EntryType::makeNamespace();
2990 else
2991 yyextra->current->section = EntryType::makeFunction();
2992
2993 if (!name.empty())
2994 {
2995 yyextra->current->name = name;
2996 }
2997 else
2998 {
2999 DString fname = yyextra->fileName;
3000 size_t index1 = fname.rfind('/');
3001 size_t index2 = fname.rfind('\\');
3002 size_t index = index1!=DString::npos && index2!=DString::npos ? std::max(index1,index2) :
3003 index1!=DString::npos ? index1 : index2;
3004 if (index!=DString::npos) fname = fname.mid(index+1);
3005 if (yyextra->mainPrograms) fname += "__" + DString().setNum(yyextra->mainPrograms);
3006 yyextra->mainPrograms++;
3007 fname = fname.prepend("__").append("__");
3008 yyextra->current->name = substitute(fname, ".", "_");
3009 }
3010 yyextra->current->type = "program";
3011 yyextra->current->fileName = yyextra->fileName;
3012 yyextra->current->bodyLine = yyextra->lineNr; // used for source reference
3013 yyextra->current->startLine = yyextra->lineNr;
3014 yyextra->current->protection = Protection::Public ;
3015 addCurrentEntry(yyscanner,true);
3016 startScope(yyscanner,yyextra->last_entry.get());
DString & setNum(short n)
Definition dstring.h:552
size_t rfind(char c, size_t pos=npos) const
Definition dstring.h:244
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:318
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
Definition dstring.h:178
DString & append(char c)
Definition dstring.h:489
DString & prepend(const char *s)
Definition dstring.h:515
DString substitute(const DString &s, const DString &src, const DString &dst)
substitute all occurrences of src in s by dst
Definition dstring.cpp:485
static void startScope(yyscan_t yyscanner, Entry *scope)
3017}

References addCurrentEntry(), DString::append(), DBG_CTX, DString::empty(), DString::mid(), DString::npos, DString::prepend(), qPrint(), DString::rfind(), DString::setNum(), startScope(), and substitute().

Referenced by addInterface().

◆ addSubprogram()

void addSubprogram ( yyscan_t yyscanner,
const DString & text )
static

Definition at line 3020 of file fortranscanner.l.

3021{
3022 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3023 DBG_CTX((stderr,"1=========> got subprog, type: %s\n",qPrint(text)));
3024 yyextra->subrCurrent.push_back(yyextra->current);
3025 yyextra->current->section = EntryType::makeFunction();
3026 DString subtype = text; subtype=subtype.lower().stripWhiteSpace();
3027 yyextra->functionLine = subtype.find("function")!=DString::npos;
3028 yyextra->current->type += " " + subtype;
3029 yyextra->current->type = yyextra->current->type.stripWhiteSpace();
3030 if (yyextra->ifType == IF_ABSTRACT)
3031 {
3032 yyextra->current->virt = Specifier::Virtual;
3033 }
3034 yyextra->current->fileName = yyextra->fileName;
3035 yyextra->current->bodyLine = yyextra->lineNr; // used for source reference start of body of routine
3036 yyextra->current->startLine = yyextra->lineNr; // used for source reference start of definition
3037 yyextra->current->args.clear();
3038 yyextra->current->argList.clear();
3039 pushBlockState(yyscanner,text);
3040 yyextra->docBlock.clear();
void clear()
Definition dstring.h:214
DString lower() const
Definition dstring.h:326
size_t find(char c, size_t pos=0) const
Definition dstring.h:239
DString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition dstring.h:337
3041}

References DString::clear(), DBG_CTX, DString::find(), IF_ABSTRACT, DString::lower(), DString::npos, pushBlockState(), qPrint(), and DString::stripWhiteSpace().

◆ applyModifiers() [1/3]

void applyModifiers ( Argument * arg,
const SymbolModifiers & mdfs )
static

Apply yyextra->modifiers stored in mdfs to the arg argument.

Definition at line 2609 of file fortranscanner.l.

2610{
2611 arg->type = applyModifiers(arg->type, mdfs);
DString type
Definition arguments.h:43
static DString applyModifiers(DString typeName, const SymbolModifiers &mdfs)
2612}

References applyModifiers(), and Argument::type.

◆ applyModifiers() [2/3]

DString applyModifiers ( DString typeName,
const SymbolModifiers & mdfs )
static

Apply yyextra->modifiers stored in mdfs to the typeName string.

Definition at line 2492 of file fortranscanner.l.

2493{
2494 if (!mdfs.dimension.empty())
2495 {
2496 if (!typeName.empty()) typeName += ", ";
2497 typeName += mdfs.dimension;
2498 }
2500 {
2501 if (!typeName.empty()) typeName += ", ";
2502 typeName += directionStrs[mdfs.direction];
2503 }
2504 if (mdfs.optional)
2505 {
2506 if (!typeName.empty()) typeName += ", ";
2507 typeName += "optional";
2508 }
2509 if (mdfs.allocatable)
2510 {
2511 if (!typeName.empty()) typeName += ", ";
2512 typeName += "allocatable";
2513 }
2514 if (mdfs.external)
2515 {
2516 if (!typeName.contains("external"))
2517 {
2518 if (!typeName.empty()) typeName += ", ";
2519 typeName += "external";
2520 }
2521 }
2522 if (mdfs.intrinsic)
2523 {
2524 if (!typeName.empty()) typeName += ", ";
2525 typeName += "intrinsic";
2526 }
2527 if (mdfs.parameter)
2528 {
2529 if (!typeName.empty()) typeName += ", ";
2530 typeName += "parameter";
2531 }
2532 if (mdfs.pointer)
2533 {
2534 if (!typeName.empty()) typeName += ", ";
2535 typeName += "pointer";
2536 }
2537 if (mdfs.target)
2538 {
2539 if (!typeName.empty()) typeName += ", ";
2540 typeName += "target";
2541 }
2542 if (mdfs.save)
2543 {
2544 if (!typeName.empty()) typeName += ", ";
2545 typeName += "save";
2546 }
2547 if (mdfs.deferred)
2548 {
2549 if (!typeName.empty()) typeName += ", ";
2550 typeName += "deferred";
2551 }
2552 if (mdfs.nonoverridable)
2553 {
2554 if (!typeName.empty()) typeName += ", ";
2555 typeName += "non_overridable";
2556 }
2557 if (mdfs.nopass)
2558 {
2559 if (!typeName.empty()) typeName += ", ";
2560 typeName += "nopass";
2561 }
2562 if (mdfs.pass)
2563 {
2564 if (!typeName.empty()) typeName += ", ";
2565 typeName += "pass";
2566 if (!mdfs.passVar.empty())
2567 typeName += "(" + mdfs.passVar + ")";
2568 }
2569 if (!mdfs.bindVar.empty())
2570 {
2571 if (!typeName.empty()) typeName += ", ";
2572 typeName += mdfs.bindVar;
2573 }
2575 {
2576 if (!typeName.empty()) typeName += ", ";
2577 typeName += "public";
2578 }
2579 else if (mdfs.protection == SymbolModifiers::PRIVATE)
2580 {
2581 if (!typeName.empty()) typeName += ", ";
2582 typeName += "private";
2583 }
2584 if (mdfs.protect)
2585 {
2586 if (!typeName.empty()) typeName += ", ";
2587 typeName += "protected";
2588 }
2589 if (mdfs.contiguous)
2590 {
2591 if (!typeName.empty()) typeName += ", ";
2592 typeName += "contiguous";
2593 }
2594 if (mdfs.volat)
2595 {
2596 if (!typeName.empty()) typeName += ", ";
2597 typeName += "volatile";
2598 }
2599 if (mdfs.value)
2600 {
2601 if (!typeName.empty()) typeName += ", ";
2602 typeName += "value";
2603 }
int contains(char c, bool cs=true) const
Definition dstring.cpp:85
static const char * directionStrs[]
Protection protection
2604
2605 return typeName;
2606}

References SymbolModifiers::allocatable, SymbolModifiers::bindVar, DString::contains(), SymbolModifiers::contiguous, SymbolModifiers::deferred, SymbolModifiers::dimension, SymbolModifiers::direction, directionStrs, DString::empty(), SymbolModifiers::external, SymbolModifiers::intrinsic, SymbolModifiers::NONE_D, SymbolModifiers::nonoverridable, SymbolModifiers::nopass, SymbolModifiers::optional, SymbolModifiers::parameter, SymbolModifiers::pass, SymbolModifiers::passVar, SymbolModifiers::pointer, SymbolModifiers::PRIVATE, SymbolModifiers::protect, SymbolModifiers::protection, SymbolModifiers::PUBLIC, SymbolModifiers::save, SymbolModifiers::target, SymbolModifiers::value, and SymbolModifiers::volat.

Referenced by applyModifiers(), applyModifiers(), and endScope().

◆ applyModifiers() [3/3]

void applyModifiers ( Entry * ent,
const SymbolModifiers & mdfs )
static

Apply yyextra->modifiers stored in mdfs to the ent entry.

Definition at line 2615 of file fortranscanner.l.

2616{
2617 ent->type = applyModifiers(ent->type, mdfs);
DString type
member type
Definition entry.h:172
2618
2620 ent->protection = Protection::Public;
2621 else if (mdfs.protection == SymbolModifiers::PRIVATE)
2622 ent->protection = Protection::Private;
Protection protection
class protection
Definition entry.h:179
2623
2624 if (mdfs.nonoverridable)
2625 ent->spec.setFinal(true);
2626 if (mdfs.nopass)
2627 ent->isStatic = true;
2628 if (mdfs.deferred)
2629 ent->virt = Specifier::Pure;
Specifier virt
virtualness of the entry
Definition entry.h:190
bool isStatic
static ?
Definition entry.h:184
TypeSpecifier spec
class/member specifiers
Definition entry.h:181
2630}

References applyModifiers(), SymbolModifiers::deferred, Entry::isStatic, SymbolModifiers::nonoverridable, SymbolModifiers::nopass, SymbolModifiers::PRIVATE, Entry::protection, SymbolModifiers::protection, SymbolModifiers::PUBLIC, Entry::spec, Entry::type, and Entry::virt.

◆ computeIndent()

int computeIndent ( const char * s)
inlinestatic

Definition at line 1706 of file fortranscanner.l.

1707{
1708 int col=0;
1709 int tabSize=Config_getInt(TAB_SIZE);
1710 const char *p=s;
1711 char c = 0;
1712 while ((c=*p++))
1713 {
1714 if (c=='\t') col+=tabSize-(col%tabSize);
1715 else if (c=='\n') col=0;
1716 else col++;
1717 }
1718 return col;
#define Config_getInt(name)
Definition config.h:34
1719}

References Config_getInt.

◆ convertFileNameFortranParserCode()

FortranFormat convertFileNameFortranParserCode ( const DString & fn)

Definition at line 2195 of file fortranscanner.l.

2196{
2197 DString ext = getFileNameExtension(fn);
2198 DString parserName = Doxygen::parserManager->getParserName(ext);
static ParserManager * parserManager
Definition doxygen.h:122
DString getParserName(const DString &extension)
Gets the name of the parser associated with given extension.
Definition parserintf.h:268
DString getFileNameExtension(const DString &fn)
Definition util.cpp:4210
2199
2200 if (parserName == "fortranfixed") return FortranFormat::Fixed;
2201 else if (parserName == "fortranfree") return FortranFormat::Free;
2202
2204}

References Fixed, Free, getFileNameExtension(), ParserManager::getParserName(), Doxygen::parserManager, and Unknown.

Referenced by convertCppComments(), and setFileName().

◆ copyEntry()

void copyEntry ( std::shared_ptr< Entry > dest,
const std::shared_ptr< Entry > & src )
static

used to copy entry to an interface module procedure

Definition at line 2233 of file fortranscanner.l.

2234{
2235 dest->type = src->type;
2236 dest->fileName = src->fileName;
2237 dest->startLine = src->startLine;
2238 dest->bodyLine = src->bodyLine;
2239 dest->endBodyLine = src->endBodyLine;
2240 dest->args = src->args;
2241 dest->argList = src->argList;
2242 dest->doc = src->doc;
2243 dest->docLine = src->docLine;
2244 dest->docFile = src->docFile;
2245 dest->brief = src->brief;
2246 dest->briefLine= src->briefLine;
2247 dest->briefFile= src->briefFile;
2248}

Referenced by resolveModuleProcedures().

◆ endScope()

bool endScope ( yyscan_t yyscanner,
Entry * scope,
bool isGlobalRoot )
static

Ends scope in fortran program: may update subprogram arguments or module variable attributes.

See also
startScope()

Definition at line 2652 of file fortranscanner.l.

2653{
2654 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2655 if (yyextra->global_scope == scope)
2656 {
2657 yyextra->global_scope = nullptr;
2658 return true;
2659 }
2660 if (yyextra->global_scope == INVALID_ENTRY)
2661 {
2662 return true;
2663 }
2664 //cout<<"end scope: "<<scope->name<<endl;
2665 if (yyextra->current_root->parent() || isGlobalRoot)
2666 {
2667 yyextra->current_root= yyextra->current_root->parent(); /* end substructure */
2668 }
2669 else // if (yyextra->current_root != scope)
2670 {
2671 fprintf(stderr,"parse error in end <scopename>\n");
2672 scanner_abort(yyscanner);
2673 return false;
2674 }
#define INVALID_ENTRY
static void scanner_abort(yyscan_t yyscanner)
2675
2676 // create new current with possibly different defaults...
2677 yyextra->current = std::make_shared<Entry>();
2678 initEntry(yyscanner);
2679
2680 // update variables or subprogram arguments with yyextra->modifiers
2681 std::map<std::string,SymbolModifiers>& mdfsMap = yyextra->modifiers[scope];
2682
2683 if (scope->section.isFunction())
2684 {
2685 // iterate all symbol yyextra->modifiers of the scope
2686 for (const auto &kv : mdfsMap)
2687 {
2688 //cout<<it.key()<<": "<<qPrint(it)<<endl;
2689 Argument *arg = findArgument(scope, kv.first);
This class contains the information about the argument of a function or template.
Definition arguments.h:27
EntryType section
entry type (see Sections);
Definition entry.h:171
static Argument * findArgument(Entry *subprog, DString name, bool byTypeName=false)
2690
2691 if (arg)
2692 {
2693 applyModifiers(arg, kv.second);
2694 }
2695 }
2696
2697 // find return type for function
2698 //cout<<"RETURN NAME "<<yyextra->modifiers[yyextra->current_root][scope->name.lower()].returnName<<endl;
2699 DString returnName = yyextra->modifiers[yyextra->current_root][scope->name.lower().str()].returnName.lower();
2700 if (yyextra->modifiers[scope].find(returnName.str())!=yyextra->modifiers[scope].end())
2701 {
2702 scope->type = yyextra->modifiers[scope][returnName.str()].type; // returning type works
2703 applyModifiers(scope, yyextra->modifiers[scope][returnName.str()]); // returning array works
2704 }
const std::string & str() const
Definition dstring.h:645
DString name
member name
Definition entry.h:173
2705
2706 }
2707 if (scope->section.isClass() && scope->spec.isInterface())
2708 { // was INTERFACE_SEC
2709 if (scope->parent() && scope->parent()->section.isFunction())
2710 { // interface within function
2711 // iterate functions of interface and
2712 // try to find types for dummy(ie. argument) procedures.
2713 //cout<<"Search in "<<scope->name<<endl;
2714 for (const auto &ce : scope->children())
2715 {
2716 if (!ce->section.isFunction())
2717 continue;
const std::vector< std::shared_ptr< Entry > > & children() const
Definition entry.h:138
Entry * parent() const
Definition entry.h:133
2718
2719 // remove prefix
2720 DString name = ce->name.lower();
2721 if (size_t ii = name.rfind(':'); ii!=DString::npos) name.remove(0, ii+1);
2722 Argument *arg = findArgument(scope->parent(), name);
2723 if (arg)
2724 {
2725 // set type of dummy procedure argument to interface
2726 arg->type = "external " + ce->type + "(";
2727 for (size_t i=0; i<ce->argList.size(); i++)
2728 {
2729 if (i > 0)
2730 {
2731 arg->type = arg->type + ", ";
2732 }
2733 const Argument &subarg = ce->argList.at(i);
2734 arg->type = arg->type + subarg.type + " " + subarg.name;
2735 }
2736 arg->type = arg->type + ")";
2737 arg->name = name;
2738 }
2739 }
2740 // clear all yyextra->modifiers of the scope
2741 yyextra->modifiers.erase(scope);
2742 scope->parent()->removeSubEntry(scope);
2743 scope = nullptr;
2744 return true;
2745 }
2746 }
2747 if (!scope->section.isFunction())
2748 { // not function section
2749 // iterate variables: get and apply yyextra->modifiers
2750 for (const auto &ce : scope->children())
2751 {
2752 if (!ce->section.isVariable() && !ce->section.isFunction() && !ce->section.isClass())
2753 continue;
DString name
Definition arguments.h:45
DString & remove(size_t index, size_t len)
Definition dstring.h:535
void removeSubEntry(const Entry *e)
Definition entry.cpp:172
2754
2755 //cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl;
2756 if (mdfsMap.find(ce->name.lower().str())!=mdfsMap.end())
2757 applyModifiers(ce.get(), mdfsMap[ce->name.lower().str()]);
2758
2759 // remove prefix for variable names
2760 if (ce->section.isVariable() || ce->section.isFunction())
2761 {
2762 if (size_t end = ce->name.rfind(':'); end!=DString::npos) ce->name.remove(0, end+1);
2763 }
2764 }
2765 }
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:181
2766
2767 // clear all yyextra->modifiers of the scope
2768 yyextra->modifiers.erase(scope);
2769
2770 // resolve procedures in types
static void resolveTypeBoundProcedures(Entry *scope)
2772
2773 return true;
2774}

References applyModifiers(), Entry::children(), end(), findArgument(), initEntry(), INVALID_ENTRY, DString::lower(), Argument::name, Entry::name, DString::npos, Entry::parent(), DString::remove(), Entry::removeSubEntry(), resolveTypeBoundProcedures(), DString::rfind(), scanner_abort(), Entry::section, Entry::spec, DString::str(), Argument::type, and Entry::type.

Referenced by parseMain().

◆ extractBind()

DString extractBind ( const DString & name)
static

remove useless spaces from bind statement

Definition at line 2310 of file fortranscanner.l.

2311{
2312 DString parensPart = extractFromParens(name);
2313 if (parensPart.length() == 1)
2314 {
2315 return "bind(C)";
2316 }
2317 else
2318 {
2319 //strip 'c'
2320 parensPart = parensPart.mid(1).stripWhiteSpace();
2321 // strip ','
2322 parensPart = parensPart.mid(1).stripWhiteSpace();
2323 // name part
2324 parensPart = parensPart.mid(4).stripWhiteSpace();
2325 // = part
2326 parensPart = parensPart.mid(1).stripWhiteSpace();
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition dstring.h:151
static DString extractFromParens(const DString &name)
2327
2328 return "bind(C, name=" + parensPart + ")";
2329 }
2330}

References extractFromParens(), DString::length(), DString::mid(), and DString::stripWhiteSpace().

Referenced by SymbolModifiers::operator|=().

◆ extractFromParens()

DString extractFromParens ( const DString & name)
static

Extracts string which resides within parentheses of provided string.

Definition at line 2292 of file fortranscanner.l.

2293{
2294 DString extracted = name;
2295 if (size_t start = extracted.find('('); start!=DString::npos)
2296 {
2297 extracted.remove(0, start+1);
2298 }
2299 if (size_t end = extracted.rfind(')'); end!=DString::npos)
2300 {
2301 size_t length = extracted.length();
2302 extracted.remove(end, length);
2303 }
2304 extracted = extracted.stripWhiteSpace();
2305
2306 return extracted;
2307}

References end(), DString::find(), DString::length(), DString::npos, DString::remove(), DString::rfind(), and DString::stripWhiteSpace().

Referenced by extractBind(), and SymbolModifiers::operator|=().

◆ findArgument()

Argument * findArgument ( Entry * subprog,
DString name,
bool byTypeName = false )
static

For debugging purposes.

Find argument with given name in subprog entry.

Definition at line 2475 of file fortranscanner.l.

2476{
2477 DString cname(name.lower());
2478 for (Argument &arg : subprog->argList)
2479 {
2480 if ((!byTypeName && arg.name.lower() == cname) ||
2481 (byTypeName && arg.type.lower() == cname)
2482 )
2483 {
2484 return &arg;
2485 }
2486 }
2487 return nullptr;
ArgumentList argList
member arguments as a list
Definition entry.h:194
2488}

References Entry::argList, DString::lower(), Argument::name, and Argument::type.

Referenced by endScope().

◆ getAmpersandAtTheStart()

int getAmpersandAtTheStart ( const char * buf,
int length )
static

Definition at line 1753 of file fortranscanner.l.

1754{
1755 for(int i=0; i<length; i++)
1756 {
1757 switch(buf[i])
1758 {
1759 case ' ':
1760 case '\t':
1761 break;
1762 case '&':
1763 return i;
1764 default:
1765 return -1;
1766 }
1767 }
1768 return -1;
1769}

◆ getAmpOrExclAtTheEnd()

int getAmpOrExclAtTheEnd ( const char * buf,
int length,
char ch )
static

Definition at line 1772 of file fortranscanner.l.

1773{
1774 // Avoid ampersands in string and yyextra->comments
1775 int parseState = Start;
1776 char quoteSymbol = 0;
1777 int ampIndex = -1;
1778 int commentIndex = -1;
1779 quoteSymbol = ch;
1780 if (ch != '\0') parseState = String;
1781
1782 for(int i=0; i<length && parseState!=Comment; i++)
1783 {
1784 // When in string, skip backslashes
1785 // Legacy code, not sure whether this is correct?
1786 if (parseState==String)
1787 {
1788 if (buf[i]=='\\') i++;
1789 }
1790
1791 switch(buf[i])
1792 {
1793 case '\'':
1794 case '"':
1795 // Close string, if quote symbol matches.
1796 // Quote symbol is set iff parseState==String
1797 if (buf[i]==quoteSymbol)
1798 {
1799 parseState = Start;
1800 quoteSymbol = 0;
1801 }
1802 // Start new string, if not already in string or comment
1803 else if (parseState==Start)
1804 {
1805 parseState = String;
1806 quoteSymbol = buf[i];
1807 }
1808 ampIndex = -1; // invalidate prev ampersand
1809 break;
1810 case '!':
1811 // When in string or comment, ignore exclamation mark
1812 if (parseState==Start)
1813 {
1814 parseState = Comment;
1815 commentIndex = i;
1816 }
1817 break;
1818 case ' ': // ignore whitespace
1819 case '\t':
1820 case '\n': // this may be at the end of line
1821 break;
1822 case '&':
1823 ampIndex = i;
1824 break;
1825 default:
1826 ampIndex = -1; // invalidate prev ampersand
1827 }
1828 }
1829
1830 if (ampIndex>=0)
1831 return ampIndex;
1832 else
1833 return commentIndex;
1834}

Referenced by prepassFixedForm().

◆ getLexerFILE()

const char * getLexerFILE ( )
inlinestatic

Definition at line 269 of file fortranscanner.l.

269{return __FILE__;}

◆ getParameter()

Argument * getParameter ( yyscan_t yyscanner,
const DString & name )
static

Get the argument name.

Definition at line 3096 of file fortranscanner.l.

3097{
3098 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3099 // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.empty()?DString("null"):docs)<<"\n";
3100 Argument *ret = nullptr;
3101 for (Argument &a:yyextra->current_root->argList)
3102 {
3103 if (a.name.lower()==name.lower())
3104 {
3105 ret=&a;
3106 //printf("parameter found: %s\n",(const char*)name);
3107 break;
3108 }
3109 } // for
3110 return ret;
3111}

References DString::lower(), and Argument::name.

Referenced by updateVariablePrepassComment().

◆ handleCommentBlock()

void handleCommentBlock ( yyscan_t yyscanner,
const DString & doc,
bool brief )
static

Definition at line 3131 of file fortranscanner.l.

3132{
3133 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3134 //printf("handleCommentBlock(doc=[%s] brief=%d yyextra->docBlockInBody=%d yyextra->docBlockJavaStyle=%d\n",
3135 // qPrint(doc),brief,yyextra->docBlockInBody,yyextra->docBlockJavaStyle);
3136
3137 bool hideInBodyDocs = Config_getBool(HIDE_IN_BODY_DOCS);
3138 if (yyextra->docBlockInBody && hideInBodyDocs)
3139 {
3140 yyextra->docBlockInBody = false;
3141 return;
3142 }
3143 DBG_CTX((stderr,"call parseCommentBlock [%s]\n",qPrint(doc)));
3144 int lineNr = brief ? yyextra->current->briefLine : yyextra->current->docLine;
3145 int position=0;
3146 bool needsEntry = false;
3147 Markdown markdown(yyextra->fileName,lineNr);
3148 GuardedSectionStack guards;
3149 DString strippedDoc = stripIndentation(doc);
3150 DString processedDoc = Config_getBool(MARKDOWN_SUPPORT) ? markdown.process(strippedDoc,lineNr) : strippedDoc;
3151 while (yyextra->commentScanner.parseCommentBlock(
3152 yyextra->thisParser,
3153 yyextra->docBlockInBody ? yyextra->subrCurrent.back().get() : yyextra->current.get(),
3154 processedDoc, // text
3155 yyextra->fileName, // file
3156 lineNr,
3157 yyextra->docBlockInBody ? false : brief,
3158 yyextra->docBlockInBody ? false : yyextra->docBlockJavaStyle,
3159 yyextra->docBlockInBody,
3160 yyextra->defaultProtection,
3161 position,
3162 needsEntry,
3163 Config_getBool(MARKDOWN_SUPPORT),
3164 &guards
3165 ))
3166 {
3167 DBG_CTX((stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry));
3168 if (needsEntry) addCurrentEntry(yyscanner,false);
3169 }
3170 DBG_CTX((stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry));
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition dstring.h:157
Helper class to process markdown formatted text.
Definition markdown.h:33
std::stack< GuardedSection > GuardedSectionStack
Definition commentscan.h:48
#define Config_getBool(name)
Definition config.h:33
DString stripIndentation(const DString &s, bool skipFirstLine)
Definition util.cpp:4683
3171
3172 if (needsEntry) addCurrentEntry(yyscanner,false);
3173 yyextra->docBlockInBody = false;
3174}

References addCurrentEntry(), Config_getBool, DString::data(), DBG_CTX, Markdown::process(), qPrint(), and stripIndentation().

Referenced by subrHandleCommentBlock(), and subrHandleCommentBlockResult().

◆ initEntry()

void initEntry ( yyscan_t yyscanner)
static

Definition at line 2944 of file fortranscanner.l.

2945{
2946 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2947 if (yyextra->typeMode)
2948 {
2949 yyextra->current->protection = yyextra->typeProtection;
2950 }
2951 else if (yyextra->current_root && yyextra->current_root->section.isClass() && yyextra->current_root->spec.isInterface())
2952 {
2953 yyextra->current->protection = Protection::Public;
2954 }
2955 else if (yyextra->current_root && yyextra->current_root->section.isFunction())
2956 {
2957 yyextra->current->protection = Protection::Private;
2958 }
2959 else
2960 {
2961 yyextra->current->protection = yyextra->defaultProtection;
2962 }
2963 yyextra->current->mtype = MethodTypes::Method;
2964 yyextra->current->virt = Specifier::Normal;
2965 yyextra->current->isStatic = false;
2966 yyextra->current->lang = SrcLangExt::Fortran;
2967 yyextra->commentScanner.initGroupInfo(yyextra->current.get());
2968}

Referenced by addCurrentEntry(), endScope(), and startScope().

◆ initParser()

void initParser ( yyscan_t yyscanner)
static

Definition at line 2938 of file fortranscanner.l.

2939{
2940 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2941 yyextra->last_entry.reset();
2942}

Referenced by parseMain().

◆ insertCharacter()

void insertCharacter ( char * contents,
int length,
int pos,
char c )
static

Definition at line 1852 of file fortranscanner.l.

1853{
1854 // shift tail by one character
1855 for(int i=length; i>pos; i--)
1856 contents[i]=contents[i-1];
1857 // set the character
1858 contents[pos] = c;
1859}

Referenced by prepassFixedForm().

◆ keyWordsFortranC()

bool keyWordsFortranC ( const char * contents)
static

Definition at line 2123 of file fortranscanner.l.

2124{
2125 static const std::unordered_set<std::string> fortran_C_keywords = {
2126 "character", "call", "close", "common", "continue",
2127 "case", "contains", "cycle", "class", "codimension",
2128 "concurrent", "contiguous", "critical"
2129 };
2130
2131 if (*contents != 'c' && *contents != 'C') return false;
2132
2133 const char *c = contents;
2134 DString keyword;
2135 while (*c && *c != ' ') {keyword += *c; c++;}
2136 keyword = keyword.lower();
2137
2138 return (fortran_C_keywords.find(keyword.str()) != fortran_C_keywords.end());
2139}

References DString::lower(), and DString::str().

Referenced by recognizeFixedForm().

◆ locatePrepassComment()

const CommentInPrepass * locatePrepassComment ( yyscan_t yyscanner,
int from,
int to )
static

Definition at line 1721 of file fortranscanner.l.

1722{
1723 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1724 //printf("Locate %d-%d\n", from, to);
1725 for (const auto &cip : yyextra->comments)
1726 { // todo: optimize
1727 int c = cip.column;
1728 //printf("Candidate %d\n", c);
1729 if (c>=from && c<=to)
1730 {
1731 // comment for previous variable or parameter
1732 return &cip;
1733 }
1734 }
1735 return nullptr;
1736}

References CommentInPrepass::column.

Referenced by updateVariablePrepassComment().

◆ newLine()

void newLine ( yyscan_t yyscanner)
static

Definition at line 1697 of file fortranscanner.l.

1698{
1699 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1700 yyextra->lineNr++;
1701 yyextra->lineNr+=yyextra->lineCountPrepass;
1702 yyextra->lineCountPrepass=0;
1703 yyextra->comments.clear();
1704}

◆ parseMain()

void parseMain ( yyscan_t yyscanner,
const DString & fileName,
const char * fileBuf,
const std::shared_ptr< Entry > & rt,
FortranFormat format )
static

Definition at line 3311 of file fortranscanner.l.

3313{
3314 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3315 char *tmpBuf = nullptr;
3316 initParser(yyscanner);
static void initParser(yyscan_t yyscanner)
3317
3318 if (fileBuf==nullptr || fileBuf[0]=='\0') return;
3319
3320 yyextra->defaultProtection = Protection::Public;
3321 yyextra->inputString = fileBuf;
3322 yyextra->inputPosition = 0;
3323 yyextra->inputStringPrepass = nullptr;
3324 yyextra->inputPositionPrepass = 0;
3325
3326 //yyextra->anonCount = 0; // don't reset per file
3327 yyextra->current_root = rt.get();
3328 yyextra->global_root = rt;
3329
3330 yyextra->isFixedForm = recognizeFixedForm(fileBuf,format);
bool recognizeFixedForm(const DString &contents, FortranFormat format)
3331
3332 if (yyextra->isFixedForm)
3333 {
3334 yyextra->fixedCommentAfter = Config_getInt(FORTRAN_COMMENT_AFTER);
3335 msg("Prepassing fixed form of {}\n", fileName);
3336 //printf("---strlen=%d\n", strlen(fileBuf));
3337 //clock_t start=clock();
#define msg(fmt,...)
Definition message.h:94
3338
3339 //printf("Input fixed form string:\n%s\n", fileBuf);
3340 //printf("===========================\n");
3341 yyextra->inputString = prepassFixedForm(fileBuf, nullptr,yyextra->fixedCommentAfter);
3342 Debug::print(Debug::FortranFixed2Free,0,"======== Fixed to Free format =========\n---- Input fixed form string ------- \n{}\n", fileBuf);
3343 Debug::print(Debug::FortranFixed2Free,0,"---- Resulting free form string ------- \n{}\n", yyextra->inputString);
3344 //printf("Resulting free form string:\n%s\n", yyextra->inputString);
3345 //printf("===========================\n");
@ FortranFixed2Free
Definition debug.h:41
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
Definition debug.h:78
const char * prepassFixedForm(const char *contents, int *hasContLine, int fixedCommentAfter)
3346
3347 //clock_t end=clock();
3348 //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC);
3349 }
3350 else if (yyextra->inputString[strlen(fileBuf)-1] != '\n')
3351 {
3352 tmpBuf = (char *)malloc(strlen(fileBuf)+2);
3353 strcpy(tmpBuf,fileBuf);
3354 tmpBuf[strlen(fileBuf)]= '\n';
3355 tmpBuf[strlen(fileBuf)+1]= '\000';
3356 yyextra->inputString = tmpBuf;
3357 }
3358
3359 yyextra->lineNr= 1 ;
3360 yyextra->fileName = fileName;
3361 msg("Parsing file {}...\n",yyextra->fileName);
3362
3363 yyextra->global_scope = rt.get();
3364 startScope(yyscanner,rt.get()); // implies yyextra->current_root = rt
3365 initParser(yyscanner);
3366 yyextra->commentScanner.enterFile(yyextra->fileName,yyextra->lineNr);
3367
3368 // add entry for the file
3369 yyextra->current = std::make_shared<Entry>();
3370 yyextra->current->lang = SrcLangExt::Fortran;
3371 yyextra->current->name = yyextra->fileName;
3372 yyextra->current->section = EntryType::makeSource();
3373 yyextra->file_root = yyextra->current;
3374 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
3375 yyextra->current->lang = SrcLangExt::Fortran;
3376
3377 fortranscannerYYrestart( nullptr, yyscanner );
3378 {
3379 BEGIN( Start );
3380 }
3381
3382 fortranscannerYYlex(yyscanner);
3383 yyextra->commentScanner.leaveFile(yyextra->fileName,yyextra->lineNr);
3384
3385 if (yyextra->global_scope && yyextra->global_scope != INVALID_ENTRY)
3386 {
3387 endScope(yyscanner,yyextra->current_root, true); // true - global root
3388 }
static bool endScope(yyscan_t yyscanner, Entry *scope, bool isGlobalRoot=false)
3389
3390 //debugCompounds(rt); //debug
3391
3392 rt->program.str(std::string());
3393 //delete yyextra->current; yyextra->current=0;
3394 yyextra->moduleProcedures.clear();
3395 if (tmpBuf)
3396 {
3397 free((char*)tmpBuf);
3398 yyextra->inputString=nullptr;
3399 }
3400 if (yyextra->isFixedForm)
3401 {
3402 free((char*)yyextra->inputString);
3403 yyextra->inputString=nullptr;
3404 }
3405
3406}

References Config_getInt, endScope(), Debug::FortranFixed2Free, initParser(), INVALID_ENTRY, msg, prepassFixedForm(), Debug::print(), recognizeFixedForm(), and startScope().

Referenced by FortranOutlineParser::parseInput().

◆ pop_state()

void pop_state ( yyscan_t yyscanner)
inlinestatic

Definition at line 3500 of file fortranscanner.l.

3501{
3502 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3503 if ( yyg->yy_start_stack_ptr <= 0 )
3504 warn(yyextra->fileName,yyextra->lineNr,"Unexpected statement '{}'",yytext );
3505 else
3506 yy_pop_state(yyscanner);
#define warn(file, line, fmt,...)
Definition message.h:97
3507}

References warn.

◆ popBlockState()

void popBlockState ( yyscan_t yyscanner)
static

Definition at line 3517 of file fortranscanner.l.

3518{
3519 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3520 if (yyextra->blockStack.empty())
3521 {
3522 warn(yyextra->fileName,yyextra->lineNr,"Internal inconsistency: empty stack while attempting popBlockState");
3523 }
3524 else
3525 {
3526 yyextra->blockStack.pop();
3527 }
3528 if (yyextra->blockStack.empty())
3529 {
3530 yyextra->blockString.clear();
3531 yyextra->blockLineNr=-1;
3532 }
3533 else
3534 {
3535 yyextra->blockString=yyextra->blockStack.top().blockString;
3536 yyextra->blockLineNr=yyextra->blockStack.top().blockLineNr;
3537 }
3538}

References warn.

◆ popBuffer()

void popBuffer ( yyscan_t yyscanner)
static

Definition at line 2223 of file fortranscanner.l.

2224{
2225 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2226 DBG_CTX((stderr, "--POP--"));
2227 yyextra->includeStackPtr --;
2228 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
2229 yy_switch_to_buffer( yyextra->includeStack[yyextra->includeStackPtr], yyscanner );
2230}

References DBG_CTX.

Referenced by FortranOutlineParser::parsePrototype().

◆ prepassFixedForm()

const char * prepassFixedForm ( const char * contents,
int * hasContLine,
int fixedCommentAfter )

Definition at line 1863 of file fortranscanner.l.

1864{
1865 int column=0;
1866 int prevLineLength=0;
1867 int prevLineAmpOrExclIndex=-1;
1868 int skipped = 0;
1869 char prevQuote = '\0';
1870 char thisQuote = '\0';
1871 bool emptyLabel=true;
1872 bool commented=false;
1873 bool inSingle=false;
1874 bool inDouble=false;
1875 bool inBackslash=false;
1876 bool fullCommentLine=true;
1877 bool artificialComment=false;
1878 bool spaces=true;
1879 int newContentsSize = (int)strlen(contents)+3; // \000, \n (when necessary) and one spare character (to avoid reallocation)
1880 char* newContents = (char*)malloc(newContentsSize);
1881 int curLine = 1;
1882 size_t sizCont;
1883
1884 int j = -1;
1885 sizCont = strlen(contents);
1886 for(size_t i=0;i<sizCont;i++) {
1887 column++;
1888 char c = contents[i];
1889 if (artificialComment && c != '\n')
1890 {
1891 if (c == '!' && spaces)
1892 {
1893 newContents[j++] = c;
1894 artificialComment = false;
1895 spaces = false;
1896 skipped = 0;
1897 continue;
1898 }
1899 else if (c == ' ' || c == '\t') continue;
1900 else
1901 {
1902 spaces = false;
1903 skipped++;
1904 continue;
1905 }
1906 }
1907
1908 j++;
1909 if (j>=newContentsSize-3) { // check for spare characters, which may be eventually used below (by & and '! ')
1910 newContents = (char*)realloc(newContents, newContentsSize+1000);
1911 newContentsSize = newContentsSize+1000;
1912 }
1913
1914 switch(c) {
1915 case '\n':
1916 if (!fullCommentLine)
1917 {
1918 prevLineLength=column;
1919 prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength,prevQuote);
1920 if (prevLineAmpOrExclIndex == -1) prevLineAmpOrExclIndex = column - 1;
1921 if (skipped)
1922 {
1923 prevLineAmpOrExclIndex = -1;
1924 skipped = 0;
1925 }
1926 }
1927 else
1928 {
1929 prevLineLength+=column;
1930 /* Even though a full comment line is not really a comment line it can be seen as one. An empty line is also seen as a comment line (small bonus) */
1931 if (hasContLine)
1932 {
1933 hasContLine[curLine - 1] = 1;
1934 }
1935 }
1936 artificialComment=false;
1937 spaces=true;
1938 fullCommentLine=true;
1939 column=0;
1940 emptyLabel=true;
1941 commented=false;
1942 newContents[j]=c;
1943 prevQuote = thisQuote;
1944 curLine++;
1945 break;
1946 case ' ':
1947 case '\t':
1948 newContents[j]=c;
1949 break;
1950 case '\000':
1951 if (hasContLine)
1952 {
1953 free(newContents);
1954 return nullptr;
1955 }
1956 newContents[j]='\000';
1957 newContentsSize = (int)strlen(newContents);
1958 if (newContents[newContentsSize - 1] != '\n')
1959 {
1960 // to be on the safe side
1961 newContents = (char*)realloc(newContents, newContentsSize+2);
1962 newContents[newContentsSize] = '\n';
1963 newContents[newContentsSize + 1] = '\000';
1964 }
1965 return newContents;
1966 case '"':
1967 case '\'':
1968 case '\\':
1969 if ((column <= fixedCommentAfter) && (column!=6) && !commented)
1970 {
1971 // we have some special cases in respect to strings and escaped string characters
1972 fullCommentLine=false;
1973 newContents[j]=c;
1974 if (c == '\\')
1975 {
1976 inBackslash = !inBackslash;
1977 break;
1978 }
1979 else if (c == '\'')
1980 {
1981 if (!inDouble)
1982 {
1983 inSingle = !inSingle;
1984 if (inSingle) thisQuote = c;
1985 else thisQuote = '\0';
1986 }
1987 break;
1988 }
1989 else if (c == '"')
1990 {
1991 if (!inSingle)
1992 {
1993 inDouble = !inDouble;
1994 if (inDouble) thisQuote = c;
1995 else thisQuote = '\0';
1996 }
1997 break;
1998 }
1999 }
2000 inBackslash = false;
2001 // fallthrough
2002 case '#':
2003 case 'C':
2004 case 'c':
2005 case '*':
2006 case '!':
2007 if ((column <= fixedCommentAfter) && (column!=6))
2008 {
2009 emptyLabel=false;
2010 if (column==1)
2011 {
2012 newContents[j]='!';
2013 commented = true;
2014 }
2015 else if ((c == '!') && !inDouble && !inSingle)
2016 {
2017 newContents[j]=c;
2018 commented = true;
2019 }
2020 else
2021 {
2022 if (!commented) fullCommentLine=false;
2023 newContents[j]=c;
2024 }
2025 break;
2026 }
2027 // fallthrough
2028 default:
2029 if (!commented && (column < 6) && ((c - '0') >= 0) && ((c - '0') <= 9))
2030 { // remove numbers, i.e. labels from first 5 positions.
2031 newContents[j]=' ';
2032 }
2033 else if (column==6 && emptyLabel)
2034 { // continuation
2035 if (!commented) fullCommentLine=false;
2036 if (c != '0')
2037 { // 0 not allowed as continuation character, see f95 standard paragraph 3.3.2.3
2038 newContents[j]=' ';
static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch)
2039
2040 if (prevLineAmpOrExclIndex==-1)
2041 { // add & just before end of previous line
2042 /* first line is not a continuation line in code, just in snippets etc. */
2043 if (curLine != 1) insertCharacter(newContents, j+1, (j+1)-6-1, '&');
2044 j++;
2045 }
2046 else
2047 { // add & just before end of previous line comment
2048 /* first line is not a continuation line in code, just in snippets etc. */
2049 if (curLine != 1) insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex+skipped, '&');
2050 skipped = 0;
2051 j++;
2052 }
2053 if (hasContLine)
2054 {
2055 hasContLine[curLine - 1] = 1;
2056 }
2057 }
2058 else
2059 {
2060 newContents[j]=c; // , just handle like space
2061 }
2062 prevLineLength=0;
2063 }
2064 else if ((column > fixedCommentAfter) && !commented)
2065 {
2066 // first non commented non blank character after position fixedCommentAfter
2067 if (c == '&')
2068 {
2069 newContents[j]=' ';
2070 }
2071 else if (c != '!')
2072 {
2073 // I'm not a possible start of doxygen comment
2074 newContents[j]=' ';
2075 artificialComment = true;
2076 spaces=true;
2077 skipped = 0;
2078 }
2079 else
2080 {
2081 newContents[j]=c;
2082 commented = true;
2083 }
2084 }
2085 else
2086 {
2087 if (!commented) fullCommentLine=false;
2088 newContents[j]=c;
2089 emptyLabel=false;
2090 }
2091 break;
2092 }
2093 }
static void insertCharacter(char *contents, int length, int pos, char c)
2094
2095 if (hasContLine)
2096 {
2097 free(newContents);
2098 return nullptr;
2099 }
2100
2101 if (j==-1) // contents was empty
2102 {
2103 newContents = (char*)realloc(newContents, 2);
2104 newContents[0] = '\n';
2105 newContents[1] = '\000';
2106 }
2107 else if (newContents[j] == '\n') // content ended with newline
2108 {
2109 newContents = (char*)realloc(newContents, j+2);
2110 newContents[j + 1] = '\000';
2111 }
2112 else // content did not end with a newline
2113 {
2114 newContents = (char*)realloc(newContents, j+3);
2115 newContents[j + 1] = '\n';
2116 newContents[j + 2] = '\000';
2117 }
2118 return newContents;
2119}

References getAmpOrExclAtTheEnd(), and insertCharacter().

Referenced by checkContLines(), and parseMain().

◆ pushBlockState()

void pushBlockState ( yyscan_t yyscanner,
const DString & text )
static

Definition at line 3509 of file fortranscanner.l.

3510{
3511 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3512 yyextra->blockString = text;
3513 yyextra->blockLineNr = yyextra->lineNr;
3514 yyextra->blockStack.emplace(yyextra->blockString,yyextra->blockLineNr);
3515}

Referenced by addInterface(), and addSubprogram().

◆ pushBuffer()

void pushBuffer ( yyscan_t yyscanner,
const DString & buffer )
static

Definition at line 2209 of file fortranscanner.l.

2210{
2211 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2212 if (yyextra->includeStackCnt <= yyextra->includeStackPtr)
2213 {
2214 yyextra->includeStackCnt++;
2215 yyextra->includeStack = (YY_BUFFER_STATE *)realloc(yyextra->includeStack, yyextra->includeStackCnt * sizeof(YY_BUFFER_STATE));
2216 }
2217 yyextra->includeStack[yyextra->includeStackPtr++] = YY_CURRENT_BUFFER;
2218 yy_switch_to_buffer(yy_scan_string(buffer.data(),yyscanner),yyscanner);
2219
2220 DBG_CTX((stderr, "--PUSH--%s", qPrint(buffer)));
2221}

References DString::data(), DBG_CTX, and qPrint().

Referenced by FortranOutlineParser::parsePrototype().

◆ recognizeFixedForm()

bool recognizeFixedForm ( const DString & contents,
FortranFormat format )

Definition at line 2142 of file fortranscanner.l.

2143{
2144 int column=0;
2145 bool skipLine=false;
2146
2147 if (format == FortranFormat::Fixed) return true;
2148 if (format == FortranFormat::Free) return false;
2149
2150 int tabSize=Config_getInt(TAB_SIZE);
2151 size_t sizCont = contents.length();
2152 for (size_t i=0;i<sizCont;i++)
2153 {
2154 column++;
2155
2156 switch(contents.at(i))
2157 {
2158 case '\n':
2159 column=0;
2160 skipLine=false;
2161 break;
2162 case '\t':
2163 column += tabSize-1;
2164 break;
2165 case ' ':
2166 break;
2167 case '\000':
2168 return false;
2169 case '#':
2170 skipLine=true;
2171 break;
2172 case 'C':
2173 case 'c':
2174 if (column==1)
2175 {
2176 return !keyWordsFortranC(contents.data()+i);
2177 }
2178 // fallthrough
2179 case '*':
2180 if (column==1) return true;
2181 if (skipLine) break;
2182 return false;
2183 case '!':
2184 if (column!=6) skipLine=true;
2185 break;
2186 default:
2187 if (skipLine) break;
2188 if (column>=7) return true;
2189 return false;
2190 }
2191 }
2192 return false;
char & at(size_t i)
Returns a reference to the character at index i.
Definition dstring.h:686
static bool keyWordsFortranC(const char *contents)
2193}

References DString::at(), Config_getInt, DString::data(), Fixed, Free, keyWordsFortranC(), and DString::length().

Referenced by convertCppComments(), FortranCodeParser::parseCode(), parseMain(), and setFileName().

◆ resolveModuleProcedures()

void resolveModuleProcedures ( yyscan_t yyscanner,
Entry * current_root )
static

fill empty interface module procedures with info from corresponding module subprogs

TODO: handle procedures in used modules

Definition at line 2255 of file fortranscanner.l.

2256{
2257 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2258 if (yyextra->moduleProcedures.empty()) return;
2259
2260 // build up map of available functions
2261 std::map<std::string,std::shared_ptr<Entry>> procMap;
2262 {
2263 for (const auto& cf: current_root->children())
2264 {
2265 if (!cf->section.isFunction())
2266 continue;
2267
2268 // remove scope from name
2269 DString name = cf->name;
2270 {
2271 if (size_t end = name.rfind(':') ; end!=DString::npos) name.remove(0, end+1);
2272 }
2273
2274 procMap.emplace(name.str(), cf);
2275 }
2276 }
2277
2278
2279 // for all module procedures
2280 for (const auto& ce1: yyextra->moduleProcedures)
2281 {
2282 if (procMap.find(ce1->name.str())!=procMap.end())
2283 {
2284 std::shared_ptr<Entry> proc = procMap[ce1->name.str()];
2285 copyEntry(ce1, proc);
2286 }
2287 } // for all interface module procedures
2288 yyextra->moduleProcedures.clear();
static void copyEntry(std::shared_ptr< Entry > dest, const std::shared_ptr< Entry > &src)
used to copy entry to an interface module procedure
2289}

References Entry::children(), copyEntry(), end(), DString::npos, DString::remove(), DString::rfind(), and DString::str().

◆ resolveTypeBoundProcedures()

void resolveTypeBoundProcedures ( Entry * scope)
static

search for types with type bound procedures (e.g. methods) and try to resolve their arguments

Definition at line 2779 of file fortranscanner.l.

2780{
2781 // map of all subroutines/functions
2782 bool procMapCreated = false;
2783 std::unordered_map<std::string,std::shared_ptr<Entry>> procMap;
2784
2785 // map of all abstract interfaces
2786 bool interfMapCreated = false;
2787 std::unordered_map<std::string,std::shared_ptr<Entry>> interfMap;
2788
2789 // iterate over all types
2790 for (const auto &ce: scope->children())
2791 {
2792 if (!ce->section.isClass())
2793 continue;
2794
2795 // handle non-"generic" non-"deferred" methods, copying the arguments from the implementation
2796 std::unordered_map<std::string,std::shared_ptr<Entry>> methodMap;
2797 for (auto &ct: ce->children())
2798 {
2799 if (!ct->section.isFunction())
2800 continue;
2801
2802 if (ct->type=="generic")
2803 continue;
2804
2805 if (ct->virt==Specifier::Pure)
2806 continue;
2807
2808 // set up the procMap
2809 if (!procMapCreated)
2810 {
2811 for (const auto &cf: scope->children())
2812 {
2813 if (cf->section.isFunction())
2814 {
2815 procMap.emplace(cf->name.str(), cf);
2816 }
2817 }
2818 procMapCreated = true;
2819 }
2820
2821 // found a (non-generic) method
2822 DString implName = ct->args;
2823 if (procMap.find(implName.str())!=procMap.end())
2824 {
2825 std::shared_ptr<Entry> proc = procMap[implName.str()];
2826 ct->args = proc->args;
2827 ct->argList = ArgumentList(proc->argList);
2828 if (ct->brief.empty())
2829 {
2830 ct->brief = proc->brief;
2831 ct->briefLine = proc->briefLine;
2832 ct->briefFile = proc->briefFile;
2833 }
2834 if (ct->doc.empty())
2835 {
2836 ct->doc = proc->doc;
2837 ct->docLine = proc->docLine;
2838 ct->docFile = proc->docFile;
2839 }
2840 methodMap.emplace(ct->name.str(), ct);
2841 }
2842 }
This class represents an function or template argument list.
Definition arguments.h:66
2843
2844 // handle "deferred" methods (pure virtual functions), duplicating with arguments from the target abstract interface
2845 for (auto &ct: ce->children())
2846 {
2847 if (!ct->section.isFunction())
2848 continue;
2849
2850 if (ct->virt != Specifier::Pure)
2851 continue;
2852
2853 // set up the procMap
2854 if (!interfMapCreated)
2855 {
2856 for(const auto &cf: scope->children())
2857 {
2858 if (cf->section.isClass() && cf->spec.isInterface() && cf->type=="abstract")
2859 {
2860 std::shared_ptr<Entry> ci = cf->children().front();
2861 interfMap.emplace(ci->name.str(), ci);
2862 }
2863 }
2864 interfMapCreated = true;
2865 }
2866
2867 // found a (non-generic) method
2868 DString implName = ct->args;
2869 if (interfMap.find(implName.str())!= interfMap.end() )
2870 {
2871 std::shared_ptr<Entry> proc = interfMap[implName.str()];
2872 ct->args = proc->args;
2873 ct->argList = ArgumentList(proc->argList);
2874 if (ct->brief.empty())
2875 {
2876 ct->brief = proc->brief;
2877 ct->briefLine = proc->briefLine;
2878 ct->briefFile = proc->briefFile;
2879 }
2880 if (ct->doc.empty())
2881 {
2882 ct->doc = proc->doc;
2883 ct->docLine = proc->docLine;
2884 ct->docFile = proc->docFile;
2885 }
2886
2887 methodMap.emplace(ct->name.str(), ct);
2888 }
2889 }
2890
2891 // handle "generic" methods (that is function overloading!), duplicating with arguments from the target method of the type
2892 {
2893 for (auto &ct: ce->children())
2894 {
2895 if (!ct->section.isFunction())
2896 continue;
2897
2898 if (ct->type!="generic")
2899 continue;
2900
2901 // found a generic method (already duplicated for each entry by the parser)
2902 DString methodName = ct->args;
2903 if (methodMap.find(methodName.str()) != methodMap.end())
2904 {
2905 std::shared_ptr<Entry> method = methodMap[methodName.str()];
2906 ct->args = method->args;
2907 ct->argList = ArgumentList(method->argList);
2908 if (ct->brief.empty())
2909 {
2910 ct->brief = method->brief;
2911 ct->briefLine = method->briefLine;
2912 ct->briefFile = method->briefFile;
2913 }
2914 if (ct->doc.empty())
2915 {
2916 ct->doc = method->doc;
2917 ct->docLine = method->docLine;
2918 ct->docFile = method->docFile;
2919 }
2920 }
2921 }
2922 }
2923 }
2924}

References Entry::children(), and DString::str().

Referenced by endScope().

◆ scanner_abort()

void scanner_abort ( yyscan_t yyscanner)
static

Definition at line 3466 of file fortranscanner.l.

3467{
3468 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3469 fprintf(stderr,"********************************************************************\n");
3470 if (yyextra->blockLineNr == -1)
3471 {
3472 fprintf(stderr,"Error in file %s line: %d, state: %d(%s)\n",
3473 qPrint(yyextra->fileName),yyextra->lineNr,YY_START,stateToString(YY_START));
3474 }
3475 else
3476 {
3477 fprintf(stderr,"Error in file %s line: %d, state: %d(%s), starting command: '%s' probable line reference: %d\n",
3478 qPrint(yyextra->fileName),yyextra->lineNr,YY_START,stateToString(YY_START),qPrint(yyextra->blockString),yyextra->blockLineNr);
3479 }
3480 fprintf(stderr,"********************************************************************\n");
static const char * stateToString(int state)
3481
3482 // empty the stack
3483 while (!yyextra->blockStack.empty()) yyextra->blockStack.pop();
3484
3485 bool start=false;
3486
3487 for (const auto &ce : yyextra->global_root->children())
3488 {
3489 if (ce == yyextra->file_root) start=true;
3490 if (start) ce->reset();
3491 }
3492
3493 // dummy call to avoid compiler warning
3494 (void)yy_top_state(yyscanner);
3495
3496 return;
3497 //exit(-1);
3498}

References qPrint(), and stateToString().

Referenced by endScope().

◆ startCommentBlock()

void startCommentBlock ( yyscan_t yyscanner,
bool brief )
static

Definition at line 3114 of file fortranscanner.l.

3115{
3116 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3117 if (brief)
3118 {
3119 yyextra->current->briefFile = yyextra->fileName;
3120 yyextra->current->briefLine = yyextra->lineNr;
3121 }
3122 else
3123 {
3124 yyextra->current->docFile = yyextra->fileName;
3125 yyextra->current->docLine = yyextra->lineNr;
3126 }
3127}

◆ startScope()

void startScope ( yyscan_t yyscanner,
Entry * scope )
static

Starts the new scope in fortran program. Consider using this function when starting module, interface, function or other program block.

See also
endScope()

Definition at line 2636 of file fortranscanner.l.

2637{
2638 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2639 //cout<<"start scope: "<<scope->name<<endl;
2640 yyextra->current_root= scope; /* start substructure */
2641
2642 yyextra->modifiers.emplace(scope, std::map<std::string,SymbolModifiers>());
2643
2644 // create new current with possibly different defaults...
2645 yyextra->current = std::make_shared<Entry>();
2646 initEntry(yyscanner);
2647}

References initEntry().

Referenced by addModule(), and parseMain().

◆ stateToString()

const char * stateToString ( int state)
static

Referenced by scanner_abort().

◆ subrHandleCommentBlock()

void subrHandleCommentBlock ( yyscan_t yyscanner,
const DString & doc,
bool brief )
static

Handle parameter description as defined after the declaration of the parameter.

Definition at line 3178 of file fortranscanner.l.

3179{
3180 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3181 DString loc_doc;
3182 loc_doc = doc.stripWhiteSpace();
3183
3184 std::shared_ptr<Entry> tmp_entry = yyextra->current;
3185 yyextra->current = yyextra->subrCurrent.back(); // temporarily switch to the entry of the subroutine / function
3186
3187 // Still in the specification section so no inbodyDocs yet, but parameter documentation
3188 yyextra->current->inbodyDocs = "";
3189
3190 // strip \\param or @param, so we can do some extra checking. We will add it later on again.
3191 if (loc_doc.stripPrefix("\\param") ||
3192 loc_doc.stripPrefix("@param")
3193 ) loc_doc = loc_doc.stripWhiteSpace();
bool stripPrefix(const DString &prefix)
Definition dstring.h:290
3194
3195 // direction as defined with the declaration of the parameter
3196 int dir1 = yyextra->modifiers[yyextra->current_root][yyextra->argName.lower().str()].direction;
3197 // in description [in] is specified
3198 if (loc_doc.lower().find(directionParam[SymbolModifiers::IN]) == 0)
3199 {
3200 // check if with the declaration intent(in) or nothing has been specified
3203 {
3204 // strip direction
3205 loc_doc = loc_doc.mid(strlen(directionParam[SymbolModifiers::IN]));
3206 loc_doc.stripWhiteSpace();
3207 // in case of empty documentation or (now) just name, consider it as no documentation
3208 if (!loc_doc.empty() && (loc_doc.lower() != yyextra->argName.lower()))
3209 {
3210 handleCommentBlock(yyscanner,DString("\n\n@param ") + directionParam[SymbolModifiers::IN] + " " +
3211 yyextra->argName + " " + loc_doc,brief);
3212 }
3213 }
3214 else
3215 {
3216 // something different specified, give warning and leave error.
3217 warn(yyextra->fileName,yyextra->lineNr, "Routine: {}{} inconsistency between intent attribute and documentation for parameter {}:",
3218 yyextra->current->name,yyextra->current->args,yyextra->argName);
3219 handleCommentBlock(yyscanner,DString("\n\n@param ") + directionParam[dir1] + " " +
3220 yyextra->argName + " " + loc_doc,brief);
3221 }
3222 }
3223 // analogous to the [in] case, here [out] direction specified
3224 else if (loc_doc.lower().find(directionParam[SymbolModifiers::OUT]) == 0)
3225 {
3228 {
3229 loc_doc = loc_doc.mid(strlen(directionParam[SymbolModifiers::OUT]));
3230 loc_doc.stripWhiteSpace();
3231 if (loc_doc.empty() || (loc_doc.lower() == yyextra->argName.lower()))
3232 {
3233 yyextra->current = tmp_entry;
3234 return;
3235 }
3236 handleCommentBlock(yyscanner,DString("\n\n@param ") + directionParam[SymbolModifiers::OUT] + " " +
3237 yyextra->argName + " " + loc_doc,brief);
3238 }
3239 else
3240 {
3241 warn(yyextra->fileName,yyextra->lineNr, "Routine: {}{} inconsistency between intent attribute and documentation for parameter {}:",
3242 yyextra->current->name,yyextra->current->args,yyextra->argName);
3243 handleCommentBlock(yyscanner,DString("\n\n@param ") + directionParam[dir1] + " " +
3244 yyextra->argName + " " + loc_doc,brief);
3245 }
3246 }
3247 // analogous to the [in] case, here [in,out] direction specified
3248 else if (loc_doc.lower().find(directionParam[SymbolModifiers::INOUT]) == 0)
3249 {
3252 {
3253 loc_doc = loc_doc.mid(strlen(directionParam[SymbolModifiers::INOUT]));
3254 loc_doc.stripWhiteSpace();
3255 if (!loc_doc.empty() && (loc_doc.lower() != yyextra->argName.lower()))
3256 {
3257 handleCommentBlock(yyscanner,DString("\n\n@param ") + directionParam[SymbolModifiers::INOUT] + " " +
3258 yyextra->argName + " " + loc_doc,brief);
3259 }
3260 }
3261 else
3262 {
3263 warn(yyextra->fileName,yyextra->lineNr, "Routine: {}{} inconsistency between intent attribute and documentation for parameter {}:",
3264 yyextra->current->name,yyextra->current->args,yyextra->argName);
3265 handleCommentBlock(yyscanner,DString("\n\n@param ") + directionParam[dir1] + " " +
3266 yyextra->argName + " " + loc_doc,brief);
3267 }
3268 }
3269 // analogous to the [in] case; here no direction specified
3270 else if (!loc_doc.empty() && (loc_doc.lower() != yyextra->argName.lower()))
3271 {
3272 handleCommentBlock(yyscanner,DString("\n\n@param ") + directionParam[dir1] + " " +
3273 yyextra->argName + " " + loc_doc,brief);
3274 }
static const char * directionParam[]
static void handleCommentBlock(yyscan_t yyscanner, const DString &doc, bool brief)
3275
3276 // reset yyextra->current back to the part inside the routine
3277 yyextra->current = tmp_entry;
3278}

References DString::back(), directionParam, DString::empty(), DString::find(), handleCommentBlock(), SymbolModifiers::IN, SymbolModifiers::INOUT, DString::lower(), DString::mid(), SymbolModifiers::NONE_D, SymbolModifiers::OUT, DString::stripPrefix(), DString::stripWhiteSpace(), and warn.

◆ subrHandleCommentBlockResult()

void subrHandleCommentBlockResult ( yyscan_t yyscanner,
const DString & doc,
bool brief )
static

Handle result description as defined after the declaration of the parameter.

Definition at line 3281 of file fortranscanner.l.

3282{
3283 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3284 DString loc_doc;
3285 loc_doc = doc.stripWhiteSpace();
3286
3287 std::shared_ptr<Entry> tmp_entry = yyextra->current;
3288 yyextra->current = yyextra->subrCurrent.back(); // temporarily switch to the entry of the subroutine / function
3289
3290 // Still in the specification section so no inbodyDocs yet, but parameter documentation
3291 yyextra->current->inbodyDocs = "";
3292
3293 // strip \\returns or @returns. We will add it later on again.
3294 if (loc_doc.stripPrefix("\\returns") ||
3295 loc_doc.stripPrefix("\\return") ||
3296 loc_doc.stripPrefix("@returns") ||
3297 loc_doc.stripPrefix("@return")
3298 ) loc_doc = loc_doc.stripWhiteSpace();
3299
3300 if (!loc_doc.empty() && (loc_doc.lower() != yyextra->argName.lower()))
3301 {
3302 handleCommentBlock(yyscanner,DString("\n\n@returns ") + loc_doc,brief);
3303 }
3304
3305 // reset yyextra->current back to the part inside the routine
3306 yyextra->current = std::move(tmp_entry);
3307}

References DString::back(), DString::empty(), handleCommentBlock(), DString::lower(), DString::stripPrefix(), and DString::stripWhiteSpace().

◆ truncatePrepass()

void truncatePrepass ( yyscan_t yyscanner,
int index )
static

Definition at line 1839 of file fortranscanner.l.

1840{
1841 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1842 size_t length = yyextra->inputStringPrepass.length();
1843 for (size_t i=index+1; i<length; i++) {
1844 if (yyextra->inputStringPrepass[i]=='!' && i<length-1 && yyextra->inputStringPrepass[i+1]=='<') { // save comment
1845 yyextra->comments.emplace_back(index, yyextra->inputStringPrepass.right(length-i-2));
1846 }
1847 }
1848 yyextra->inputStringPrepass.resize(index);
1849}

◆ updateVariablePrepassComment()

void updateVariablePrepassComment ( yyscan_t yyscanner,
int from,
int to )
static

Definition at line 1738 of file fortranscanner.l.

1739{
1740 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1741 const CommentInPrepass *c = locatePrepassComment(yyscanner,from, to);
1742 if (c && yyextra->vtype == V_VARIABLE)
1743 {
1744 yyextra->last_entry->brief = c->str;
1745 }
1746 else if (c && yyextra->vtype == V_PARAMETER)
1747 {
1748 Argument *parameter = getParameter(yyscanner,yyextra->argName);
1749 if (parameter) parameter->docs = c->str;
1750 }
DString docs
Definition arguments.h:48
@ V_VARIABLE
@ V_PARAMETER
static const CommentInPrepass * locatePrepassComment(yyscan_t yyscanner, int from, int to)
static Argument * getParameter(yyscan_t yyscanner, const DString &name)
1751}

References Argument::docs, getParameter(), locatePrepassComment(), CommentInPrepass::str, V_PARAMETER, and V_VARIABLE.

◆ yylex()

int yylex ( yyscan_t yyscanner)

fortran parsing states

comment parsing states prototype parsing

Definition at line 377 of file fortranscanner.l.

381 {BS}[&]*{BS}!.*\n { /* skip lines with just comment. Note code was in free format or has been converted to it */
382 yyextra->lineCountPrepass ++;
383 }
384<Prepass>^{BS}\n { /* skip empty lines */
385 yyextra->lineCountPrepass ++;
386 }
387<*>^.*\n { // prepass: look for line continuations
388 yyextra->functionLine = false;
389
390 DBG_CTX((stderr, "---%s", yytext));
391
392 int indexStart = getAmpersandAtTheStart(yytext, (int)yyleng);
393 int indexEnd = getAmpOrExclAtTheEnd(yytext, (int)yyleng, '\0');
394 if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp
395 {
396 indexEnd=-1;
397 }
static int getAmpersandAtTheStart(const char *buf, int length)
398
399 if (indexEnd<0)
400 { // ----- no ampersand as line continuation
401 if (YY_START == Prepass)
402 { // last line in "continuation"
403
404 // Only take input after initial ampersand
405 yyextra->inputStringPrepass+=(const char*)(yytext+(indexStart+1));
406
407 //printf("BUFFER:%s\n", (const char*)yyextra->inputStringPrepass);
408 pushBuffer(yyscanner,yyextra->inputStringPrepass);
409 yyextra->colNr = 0;
410 pop_state(yyscanner);
411 }
412 else
413 { // simple line
414 yyextra->colNr = 0;
415 REJECT;
416 }
417 }
418 else
419 { // ----- line with continuation
420 if (YY_START != Prepass)
421 {
422 yyextra->comments.clear();
423 yyextra->inputStringPrepass=DString();
424 yy_push_state(Prepass,yyscanner);
425 }
static void pushBuffer(yyscan_t yyscanner, const DString &buffer)
static void pop_state(yyscan_t yyscanner)
426
427 size_t length = yyextra->inputStringPrepass.length();
428
429 // Only take input after initial ampersand
430 yyextra->inputStringPrepass+=(const char*)(yytext+(indexStart+1));
431 yyextra->lineCountPrepass ++;
432
433 // cut off & and remove following comment if present
434 truncatePrepass(yyscanner,static_cast<int>(length) + indexEnd - indexStart - 1);
435 }
436 }
static void truncatePrepass(yyscan_t yyscanner, int index)
437
438
439 /*------ ignore strings that are not initialization strings */
440<String>\"|\' { // string ends with next quote without previous backspace
441 if (yytext[0]!=yyextra->stringStartSymbol)
442 {
443 yyextra->colNr -= (int)yyleng;
444 REJECT;
445 } // single vs double quote
446 if (yy_top_state(yyscanner) == Initialization ||
447 yy_top_state(yyscanner) == ArrayInitializer)
448 {
449 yyextra->initializer+=yytext;
450 }
451 pop_state(yyscanner);
452 }
453<String>[\x80-\xFF]* |
454<String>. { if (yy_top_state(yyscanner) == Initialization ||
455 yy_top_state(yyscanner) == ArrayInitializer)
456 {
457 yyextra->initializer+=yytext;
458 }
459 }
460<*>\"|\' { /* string starts */
461 if (YY_START == StrIgnore)
462 { yyextra->colNr -= (int)yyleng;
463 REJECT;
464 }; // ignore in simple yyextra->comments
465 yy_push_state(YY_START,yyscanner);
466 if (yy_top_state(yyscanner) == Initialization ||
467 yy_top_state(yyscanner) == ArrayInitializer)
468 {
469 yyextra->initializer+=yytext;
470 }
471 yyextra->stringStartSymbol=yytext[0]; // single or double quote
472 BEGIN(String);
473 }
474
475 /*------ ignore simple comment (not documentation yyextra->comments) */
476
477<*>"!"/([^<>\n]|"<ff>"|"<FF>") { if (YY_START == String || YY_START == DocCopyBlock)
478 { yyextra->colNr -= (int)yyleng;
479 REJECT;
480 } // "!" is ignored in strings
481 // skip comment line (without docu yyextra->comments "!>" "!<" )
482 /* ignore further "!" and ignore yyextra->comments in Strings */
483 if ((YY_START != StrIgnore) && (YY_START != String))
484 {
485 yy_push_state(YY_START,yyscanner);
486 BEGIN(StrIgnore);
487 yyextra->debugStr="*!";
488 DBG_CTX((stderr,"start comment %d\n",yyextra->lineNr));
489 }
490 }
491<StrIgnore>.?/\n { pop_state(yyscanner); // comment ends with endline character
492 DBG_CTX((stderr,"end comment %d %s\n",yyextra->lineNr,qPrint(yyextra->debugStr)));
493 } // comment line ends
494<StrIgnore>[\x80-\xFF]* |
495<StrIgnore>. { yyextra->debugStr+=yytext; }
496
497
498 /*------ use handling ------------------------------------------------------------*/
499
500<Start,ModuleBody,SubprogBody>"use"{BS_} {
501 if (YY_START == Start)
502 {
503 addModule(yyscanner);
504 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
505 yy_push_state(ModuleBody,yyscanner); //anon program
506 }
507 yy_push_state(Use,yyscanner);
508 }
509<Use>{ID} {
510 DBG_CTX((stderr,"using dir %s\n",yytext));
511 yyextra->current->name=yytext;
512 yyextra->current->name=yyextra->current->name.lower();
513 yyextra->current->fileName = yyextra->fileName;
514 yyextra->current->section=EntryType::makeUsingDir();
515 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
516 yyextra->current->lang = SrcLangExt::Fortran;
517 pop_state(yyscanner);
518 }
519<Use>{ID}/, {
520 yyextra->useModuleName=yytext;
521 yyextra->useModuleName=yyextra->useModuleName.lower();
522 }
523<Use>,{BS}"ONLY" { BEGIN(UseOnly);
524 }
525<UseOnly>{BS},{BS} {}
526<UseOnly>{ID} {
527 yyextra->current->name= yyextra->useModuleName+"::"+yytext;
528 yyextra->current->name=yyextra->current->name.lower();
529 yyextra->current->fileName = yyextra->fileName;
530 yyextra->current->section=EntryType::makeUsingDecl();
531 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
532 yyextra->current->lang = SrcLangExt::Fortran;
533 }
534<Use,UseOnly>"\n" {
535 yyextra->colNr -= 1;
536 unput(*yytext);
537 pop_state(yyscanner);
538 }
539
540 /* INTERFACE definitions */
541<Start,ModuleBody,SubprogBody>{
542^{BS}interface{IDSYM}+ { /* variable with interface prefix */ }
543^{BS}interface { yyextra->ifType = IF_SPECIFIC;
544 yy_push_state(InterfaceBody,yyscanner);
545 // do not start a scope here, every
546 // interface body is a scope of its own
547 }
548
549^{BS}abstract{BS_}interface { yyextra->ifType = IF_ABSTRACT;
550 yy_push_state(InterfaceBody,yyscanner);
551 // do not start a scope here, every
552 // interface body is a scope of its own
553 }
554
555^{BS}interface{BS_}{ID}{ARGS}? { yyextra->ifType = IF_GENERIC;
556 yyextra->current->bodyLine = yyextra->lineNr + yyextra->lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
557 yy_push_state(InterfaceBody,yyscanner);
558
559 // extract generic name
560 DString name = DString(yytext).stripWhiteSpace();
561 name = name.mid(9).stripWhiteSpace().lower();
562 addInterface(yyscanner,name, yyextra->ifType);
563 startScope(yyscanner,yyextra->last_entry.get());
564 }
static void addInterface(yyscan_t yyscanner, DString name, InterfaceType type)
565}
566
567<InterfaceBody>^{BS}end{BS}interface({BS_}{ID})? {
568 // end scope only if GENERIC interface
569 if (yyextra->ifType == IF_GENERIC)
570 {
571 yyextra->last_entry->parent()->endBodyLine = yyextra->lineNr - 1;
572 }
573 if (yyextra->ifType == IF_GENERIC && !endScope(yyscanner,yyextra->current_root))
574 {
575 yyterminate();
576 }
577 yyextra->ifType = IF_NONE;
578 pop_state(yyscanner);
579 }
#define yyterminate()
580<InterfaceBody>module{BS}procedure { yy_push_state(YY_START,yyscanner);
581 BEGIN(ModuleProcedure);
582 }
583<ModuleProcedure>{ID} { DString name = DString(yytext).lower();
584 if (yyextra->ifType == IF_ABSTRACT || yyextra->ifType == IF_SPECIFIC)
585 {
586 addInterface(yyscanner,name, yyextra->ifType);
587 startScope(yyscanner,yyextra->last_entry.get());
588 }
589
590 yyextra->current->section = EntryType::makeFunction();
591 yyextra->current->name = name;
592 yyextra->moduleProcedures.push_back(yyextra->current);
593 addCurrentEntry(yyscanner,true);
594 }
void push_back(char c)
Definition dstring.h:202
595<ModuleProcedure>"\n" { yyextra->colNr -= 1;
596 unput(*yytext);
597 pop_state(yyscanner);
598 }
599<InterfaceBody>. {}
600
601 /*-- Contains handling --*/
602<Start>^{BS}{CONTAINS}/({BS}|\n|!|;) {
603 if (YY_START == Start)
604 {
605 addModule(yyscanner);
606 yy_push_state(ModuleBodyContains,yyscanner); //anon program
607 }
608 }
609<ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!|;) { BEGIN(ModuleBodyContains); }
610<SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!|;) { BEGIN(SubprogBodyContains); }
611<TypedefBody>^{BS}{CONTAINS}/({BS}|\n|!|;) { BEGIN(TypedefBodyContains); }
612
613 /*------ module handling ------------------------------------------------------------*/
614<Start>block{BS}data{BS}{ID_} { //
615 yyextra->vtype = V_IGNORE;
616 yy_push_state(BlockData,yyscanner);
617 yyextra->defaultProtection = Protection::Public;
618 }
@ V_IGNORE
619<Start>module|program{BS_} { //
620 yyextra->vtype = V_IGNORE;
621 if (yytext[0]=='m' || yytext[0]=='M')
622 {
623 yy_push_state(Module,yyscanner);
624 }
625 else
626 {
627 yy_push_state(Program,yyscanner);
628 }
629 yyextra->defaultProtection = Protection::Public;
630 }
631<BlockData>^{BS}"end"({BS}(block{BS}data)({BS_}{ID})?)?{BS}/(\n|!|;) { // end block data
632 //if (!endScope(yyscanner,yyextra->current_root))
633 // yyterminate();
634 yyextra->defaultProtection = Protection::Public;
635 pop_state(yyscanner);
636 }
637<Start,ModuleBody,ModuleBodyContains>"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!|;) { // end module
638 resolveModuleProcedures(yyscanner,yyextra->current_root);
639 if (!endScope(yyscanner,yyextra->current_root))
640 {
641 yyterminate();
642 }
643 yyextra->defaultProtection = Protection::Public;
644 if (yyextra->global_scope)
645 {
646 if (yyextra->global_scope != INVALID_ENTRY)
647 {
648 yy_push_state(Start,yyscanner);
649 }
650 else
651 {
652 pop_state(yyscanner); // cannot pop artrificial entry
653 }
654 }
655 else
656 {
657 yy_push_state(Start,yyscanner);
658 yyextra->global_scope = INVALID_ENTRY; // signal that the yyextra->global_scope has already been used.
659 }
660 popBlockState(yyscanner);
661 }
static void resolveModuleProcedures(yyscan_t yyscanner, Entry *current_root)
fill empty interface module procedures with info from corresponding module subprogs
static void popBlockState(yyscan_t yyscanner)
662<Module>{ID} {
663 addModule(yyscanner, DString(yytext), true);
664 pushBlockState(yyscanner,DString("module ")+yytext);
665 BEGIN(ModuleBody);
666 }
667<Program>{ID} {
668 addModule(yyscanner, DString(yytext), false);
669 pushBlockState(yyscanner,DString("program ")+yytext);
670 BEGIN(ModuleBody);
671 }
672
673 /*------- access specification --------------------------------------------------------------------------*/
674
675<ModuleBody,TypedefBody,TypedefBodyContains>private/{BS}(\n|"!") {
676 yyextra->defaultProtection = Protection::Private;
677 yyextra->current->protection = yyextra->defaultProtection ;
678 }
679<ModuleBody,TypedefBody,TypedefBodyContains>public/{BS}(\n|"!") {
680 yyextra->defaultProtection = Protection::Public;
681 yyextra->current->protection = yyextra->defaultProtection ;
682 }
683
684 /*------- type definition -------------------------------------------------------------------------------*/
685
686<ModuleBody>^{BS}type{BS}"=" {}
687<Start,ModuleBody>^{BS}type/[^a-z0-9_] {
688 if (YY_START == Start)
689 {
690 addModule(yyscanner,DString());
691 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
692 yy_push_state(ModuleBody,yyscanner); //anon program
693 }
694
695 yy_push_state(Typedef,yyscanner);
696 yyextra->current->protection = Protection::Package; // invalid in Fortran, replaced below
697 yyextra->typeProtection = Protection::Public;
698 yyextra->typeMode = true;
699 }
700<Typedef>{
701{COMMA} {}
702
703{BS}"::"{BS} {}
704
705abstract {
706 yyextra->current->spec.setAbstractClass(true);
707 }
708extends{ARGS} {
709 DString basename = extractFromParens(yytext).lower();
710 yyextra->current->extends.emplace_back(basename, Protection::Public, Specifier::Normal);
711 }
712public {
713 yyextra->current->protection = Protection::Public;
714 }
715private {
716 yyextra->current->protection = Protection::Private;
717 }
718{LANGUAGE_BIND_SPEC} {
719 /* ignored for now */
720 }
721{ID} { /* type name found */
722 yyextra->current->section = EntryType::makeClass();
723 yyextra->current->spec.setStruct(true);
724 yyextra->current->name = yytext;
725 yyextra->current->fileName = yyextra->fileName;
726 yyextra->current->bodyLine = yyextra->lineNr;
727 yyextra->current->startLine = yyextra->lineNr;
728
729 /* if type is part of a module, mod name is necessary for output */
730 if (yyextra->current_root &&
731 (yyextra->current_root->section.isClass() ||
732 yyextra->current_root->section.isNamespace()))
733 {
734 yyextra->current->name = yyextra->current_root->name + "::" + yyextra->current->name;
735 }
736
737 // set modifiers to allow adjusting public/private in surrounding module scope
738 if( yyextra->current->protection == Protection::Package )
739 {
740 yyextra->current->protection = yyextra->defaultProtection;
741 }
742 else if( yyextra->current->protection == Protection::Public )
743 {
744 yyextra->modifiers[yyextra->current_root][yyextra->current->name.lower().str()] |= DString("public");
745 }
746 else if( yyextra->current->protection == Protection::Private )
747 {
748 yyextra->modifiers[yyextra->current_root][yyextra->current->name.lower().str()] |= DString("private");
749 }
750
751 addCurrentEntry(yyscanner,true);
752 startScope(yyscanner,yyextra->last_entry.get());
753 BEGIN(TypedefBody);
754 }
755}
756
757<TypedefBodyContains>{ /* Type Bound Procedures */
758^{BS}PROCEDURE{ARGS}? {
759 yyextra->current->type = DString(yytext).simplifyWhiteSpace().lower();
760 }
DString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple internal white...
Definition dstring.cpp:127
761^{BS}final {
762 yyextra->current->spec.setFinal(true);
763 yyextra->current->type = DString(yytext).simplifyWhiteSpace();
764 }
765^{BS}generic {
766 yyextra->current->type = DString(yytext).simplifyWhiteSpace();
767 }
768{COMMA} {
769 }
770{ATTR_SPEC} {
771 yyextra->currentModifiers |= DString(yytext).stripWhiteSpace();
772 }
773{BS}"::"{BS} {
774 }
775{ID} {
776 DString name = yytext;
777 yyextra->modifiers[yyextra->current_root][name.lower().str()] |= yyextra->currentModifiers;
778 yyextra->current->section = EntryType::makeFunction();
779 yyextra->current->name = name;
780 // check for procedure(name)
781 if (yyextra->current->type.find('(')!=DString::npos)
782 {
783 yyextra->current->args = extractFromParens(yyextra->current->type).stripWhiteSpace();
784 }
785 else
786 {
787 yyextra->current->args = name.lower(); // target procedure name if no => is given
788 }
789 yyextra->current->fileName = yyextra->fileName;
790 yyextra->current->bodyLine = yyextra->lineNr;
791 yyextra->current->startLine = yyextra->lineNr;
792 addCurrentEntry(yyscanner,true);
793 }
794{BS}"=>"[^(\n|\!)]* { /* Specific bindings come after the ID. */
795 DString tmp = yytext;
796 size_t i = tmp.find("=>");
797 if (i!=DString::npos)
798 {
799 tmp.remove(0, i+2);
800 }
801 tmp = tmp.simplifyWhiteSpace().lower();
802 if (yyextra->last_entry->type == "generic")
803 {
804 // duplicate entries for each overloaded variant
805 // (parse through medhod1,method2, methodN, ...
806 //printf("Parsing through %s for generic method %s.\n", tmp.data(), last_entry->name.data());
807 i = tmp.find(',');
808 while (i!=DString::npos && i>0)
809 {
810 copyEntry(yyextra->current, yyextra->last_entry);
811 yyextra->current->name = yyextra->last_entry->name;
812 yyextra->current->section = EntryType::makeFunction();
813 yyextra->last_entry->args = tmp.left(i).stripWhiteSpace();
814 //printf("Found %s.\n", last_entry->args.data());
815 addCurrentEntry(yyscanner,true);
816 tmp = tmp.remove(0,i+1).stripWhiteSpace();
817 i = tmp.find(',');
818 }
819 }
820 //printf("Target function: %s\n", tmp.data());
821 yyextra->last_entry->args = tmp;
822 }
DString left(size_t len) const
Definition dstring.h:306
823"\n" {
824 yyextra->currentModifiers = SymbolModifiers();
825 newLine(yyscanner);
826 yyextra->docBlock.clear();
827 }
static void newLine(yyscan_t yyscanner)
Holds yyextra->modifiers (ie attributes) for one symbol (variable, function, etc).
828}
829
830
831<TypedefBody,TypedefBodyContains>{
832^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!|;) { /* end type definition */
833 yyextra->last_entry->parent()->endBodyLine = yyextra->lineNr;
834 if (!endScope(yyscanner,yyextra->current_root))
835 {
836 yyterminate();
837 }
838 yyextra->typeMode = false;
839 pop_state(yyscanner);
840 }
841^{BS}"end"{BS}/(\n|!|;) { /* incorrect end type definition */
842 warn(yyextra->fileName,yyextra->lineNr, "Found 'END' instead of 'END TYPE'");
843 yyextra->last_entry->parent()->endBodyLine = yyextra->lineNr;
844 if (!endScope(yyscanner,yyextra->current_root))
845 {
846 yyterminate();
847 }
848 yyextra->typeMode = false;
849 pop_state(yyscanner);
850 }
851}
852
853 /*------- module/global/typedef variable ---------------------------------------------------*/
854
855<SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!|;) {
856 //
857 // ABSTRACT and specific interfaces are stored
858 // in a scope of their own, even if multiple
859 // are group in one INTERFACE/END INTERFACE block.
860 //
861 if (yyextra->ifType == IF_ABSTRACT || yyextra->ifType == IF_SPECIFIC)
862 {
863 endScope(yyscanner,yyextra->current_root);
864 yyextra->last_entry->endBodyLine = yyextra->lineNr - 1;
865 }
866 yyextra->current_root->endBodyLine = yyextra->lineNr - 1;
867
868 if (!endScope(yyscanner,yyextra->current_root))
869 {
870 yyterminate();
871 }
872 yyextra->subrCurrent.pop_back();
873 yyextra->vtype = V_IGNORE;
874 popBlockState(yyscanner);
875 pop_state(yyscanner) ;
876 }
877<BlockData>{
878{ID} {
879 }
880}
881<Start,ModuleBody,TypedefBody,SubprogBody,FEnum>{
882^{BS}{TYPE_SPEC}/{SEPARATE} {
883 yyextra->last_enum.reset();
884 if (YY_START == FEnum)
885 {
886 yyextra->argType = "@"; // enum marker
887 }
888 else
889 {
890 yyextra->argType = DString(yytext).simplifyWhiteSpace().lower();
891 }
892 yyextra->current->bodyLine = yyextra->lineNr + 1;
893 yyextra->current->endBodyLine = yyextra->lineNr + yyextra->lineCountPrepass;
894 /* variable declaration starts */
895 if (YY_START == Start)
896 {
897 addModule(yyscanner);
898 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
899 yy_push_state(ModuleBody,yyscanner); //anon program
900 }
901 yy_push_state(AttributeList,yyscanner);
902 }
903{EXTERNAL_STMT}/({BS}"::"|{BS_}{ID}) {
904 /* external can be a "type" or an attribute */
905 if (YY_START == Start)
906 {
907 addModule(yyscanner);
908 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
909 yy_push_state(ModuleBody,yyscanner); //anon program
910 }
911 DString tmp = yytext;
912 yyextra->currentModifiers |= tmp.stripWhiteSpace();
913 yyextra->argType = DString(yytext).simplifyWhiteSpace().lower();
914 yy_push_state(AttributeList,yyscanner);
915 }
916{ATTR_STMT}/{BS_}{ID} |
917{ATTR_STMT}/{BS}"::" {
918 /* attribute statement starts */
919 DBG_CTX((stderr,"5=========> Attribute statement: %s\n", yytext));
920 if (YY_START == Start)
921 {
922 addModule(yyscanner);
923 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
924 yy_push_state(ModuleBody,yyscanner); //anon program
925 }
926 DString tmp = yytext;
927 yyextra->currentModifiers |= tmp.stripWhiteSpace();
928 yyextra->argType="";
929 yy_push_state(YY_START,yyscanner);
930 BEGIN( AttributeList ) ;
931 }
932"common" {
933 if (YY_START == Start)
934 {
935 addModule(yyscanner);
936 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
937 yy_push_state(ModuleBody,yyscanner); //anon program
938 }
939 }
940{ID} {
941 if (YY_START == Start && DString(yytext).stripWhiteSpace().lower()!="include")
942 {
943 addModule(yyscanner);
944 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
945 yy_push_state(ModuleBody,yyscanner); //anon program
946 }
947 }
std::string_view stripWhiteSpace(std::string_view s)
Given a string view s, returns a new, narrower view on that string, skipping over any leading or trai...
Definition stringutil.h:75
948^{BS}"type"{BS_}"is"/{BT_} {}
949^{BS}"type"{BS}"=" {}
950^{BS}"class"{BS_}"is"/{BT_} {}
951^{BS}"class"{BS_}"default" {}
952}
953<AttributeList>{
954{COMMA} {}
955{BS} {}
956{LANGUAGE_BIND_SPEC} {
957 yyextra->currentModifiers |= yytext;
958 }
959{ATTR_SPEC}. { /* update yyextra->current yyextra->modifiers when it is an ATTR_SPEC and not a variable name */
960 /* buyyextra->625519 */
961 char chr = yytext[(int)yyleng-1];
962 if (isId(chr))
963 {
964 yyextra->colNr -= (int)yyleng;
965 REJECT;
966 }
967 else
968 {
969 DString tmp = yytext;
970 tmp = tmp.left(tmp.length() - 1);
971 yyextra->colNr -= 1;
972 unput(yytext[(int)yyleng-1]);
973 yyextra->currentModifiers |= (tmp);
974 }
975 }
bool isId(char c)
Returns true if c is a valid character for an identifier.
Definition dstring.h:895
976"::" { /* end attribute list */
977 BEGIN( FVariable );
978 }
979. { /* unknown attribute, consider variable name */
980 //cout<<"start variables, unput "<<*yytext<<endl;
981 yyextra->colNr -= 1;
982 unput(*yytext);
983 BEGIN( FVariable );
984 }
985}
986
987<FVariable>{BS} {}
988<FVariable>{OPERATOR_ID} { /* parse operator access statements "public :: operator(==)" */
989 DString name = DString(yytext).stripWhiteSpace().lower();
990 /* if variable/type/etc is part of a module, mod name is necessary for output */
991 // get surrounding state
992 int currentState = YY_START;
993 pop_state(yyscanner);
994 int outerState = YY_START;
995 yy_push_state(currentState,yyscanner);
996 if( outerState == Start || outerState == ModuleBody )
997 {
998 if ((yyextra->current_root) &&
999 (yyextra->current_root->section.isClass() ||
1000 yyextra->current_root->section.isNamespace()))
1001 {
1002 name = yyextra->current_root->name + "::" + name;
1003 }
1004 }
1005 /* remember attributes for the symbol */
1006 yyextra->modifiers[yyextra->current_root][name.str()] |= yyextra->currentModifiers;
1007 }
1008<FVariable>{ID} { /* parse variable declaration */
1009 //cout << "5=========> got variable: " << yyextra->argType << "::" << yytext << endl;
1010 /* work around for bug in DString.replace (DString works) */
1011 DString name=yytext;
1012 name = name.lower();
1013 /* if variable/type/etc is part of a module, mod name is necessary for output */
1014 if ((yyextra->current_root) && yyextra->current_root->section.isNamespace())
1015 {
1016 name = yyextra->current_root->name + "::" + name;
1017 }
1018 /* remember attributes for the symbol */
1019 yyextra->modifiers[yyextra->current_root][name.lower().str()] |= yyextra->currentModifiers;
1020 yyextra->argName= name;
1021
1022 yyextra->vtype= V_IGNORE;
1023 if (!yyextra->argType.empty() && !yyextra->current_root->section.isFunction())
1024 { // new variable entry
1025 yyextra->vtype = V_VARIABLE;
1026 yyextra->current->section = EntryType::makeVariable();
1027 yyextra->current->name = yyextra->argName;
1028 yyextra->current->type = yyextra->argType;
1029 yyextra->current->fileName = yyextra->fileName;
1030 yyextra->current->bodyLine = yyextra->lineNr; // used for source reference
1031 yyextra->current->startLine = yyextra->lineNr;
1032 if (yyextra->argType == "@")
1033 {
1034 yyextra->current_root->copyToSubEntry(yyextra->current);
1035 // add to the scope surrounding the enum (copy!)
1036 yyextra->last_enum = yyextra->current;
1037 yyextra->current_root->parent()->moveToSubEntryAndRefresh(yyextra->current);
1038 initEntry(yyscanner);
1039 }
1040 else
1041 {
1042 addCurrentEntry(yyscanner,true);
1043 }
1044 }
1045 else if (!yyextra->argType.empty())
1046 { // declaration of parameter list: add type for corr. parameter
1047 Argument *parameter = getParameter(yyscanner,yyextra->argName);
1048 if (parameter)
1049 {
1050 yyextra->vtype= V_PARAMETER;
1051 if (!yyextra->argType.empty()) parameter->type=yyextra->argType.stripWhiteSpace();
1052 if (!yyextra->docBlock.empty())
1053 {
1054 subrHandleCommentBlock(yyscanner,yyextra->docBlock,true);
1055 }
1056 }
1057 // save, it may be function return type
1058 if (parameter)
1059 {
1060 yyextra->modifiers[yyextra->current_root][name.lower().str()].type = yyextra->argType;
1061 }
1062 else
1063 {
1064 if ((yyextra->current_root->name.lower() == yyextra->argName.lower()) ||
1065 (yyextra->modifiers[yyextra->current_root->parent()][yyextra->current_root->name.lower().str()].returnName.lower() == yyextra->argName.lower()))
1066 {
1067 size_t strt = yyextra->current_root->type.find("function");
1068 DString lft;
1069 DString rght;
1070 if (strt != DString::npos)
1071 {
1072 yyextra->vtype = V_RESULT;
1073 lft = "";
1074 rght = "";
1075 if (strt != 0) lft = yyextra->current_root->type.left(strt).stripWhiteSpace();
1076 if ((yyextra->current_root->type.length() - strt - strlen("function"))!= 0)
1077 {
1078 rght = yyextra->current_root->type.right(yyextra->current_root->type.length() - strt - (int)strlen("function")).stripWhiteSpace();
1079 }
1080 yyextra->current_root->type = lft;
1081 if (rght.length() > 0)
1082 {
1083 if (yyextra->current_root->type.length() > 0) yyextra->current_root->type += " ";
1084 yyextra->current_root->type += rght;
1085 }
1086 if (yyextra->argType.stripWhiteSpace().length() > 0)
1087 {
1088 if (yyextra->current_root->type.length() > 0) yyextra->current_root->type += " ";
1089 yyextra->current_root->type += yyextra->argType.stripWhiteSpace();
1090 }
1091 if (yyextra->current_root->type.length() > 0) yyextra->current_root->type += " ";
1092 yyextra->current_root->type += "function";
1093 if (!yyextra->docBlock.empty())
1094 {
1095 subrHandleCommentBlockResult(yyscanner,yyextra->docBlock,true);
1096 }
1097 }
1098 else
1099 {
1100 yyextra->current_root->type += " " + yyextra->argType.stripWhiteSpace();
1101 }
1102 yyextra->current_root->type = yyextra->current_root->type.stripWhiteSpace();
1103 yyextra->modifiers[yyextra->current_root][name.lower().str()].type = yyextra->current_root->type;
1104 }
1105 else
1106 {
1107 yyextra->modifiers[yyextra->current_root][name.lower().str()].type = yyextra->argType;
1108 }
1109 }
1110 // any accumulated doc for argument should be emptied,
1111 // because it is handled other way and this doc can be
1112 // unexpectedly passed to the next member.
1113 yyextra->current->doc.clear();
1114 yyextra->current->brief.clear();
1115 }
1116 }
DString right(size_t len) const
Definition dstring.h:311
@ V_RESULT
static void subrHandleCommentBlockResult(yyscan_t yyscanner, const DString &doc, bool brief)
Handle result description as defined after the declaration of the parameter.
static void subrHandleCommentBlock(yyscan_t yyscanner, const DString &doc, bool brief)
Handle parameter description as defined after the declaration of the parameter.
1117<FVariable>{ARGS} { /* dimension of the previous entry. */
1118 DString name(yyextra->argName);
1119 DString attr("dimension");
1120 attr += yytext;
1121 yyextra->modifiers[yyextra->current_root][name.lower().str()] |= attr;
1122 }
1123<FVariable>{COMMA} { //printf("COMMA: %d<=..<=%d\n", yyextra->colNr-(int)yyleng, yyextra->colNr);
1124 // locate !< comment
1125 updateVariablePrepassComment(yyscanner,yyextra->colNr-(int)yyleng, yyextra->colNr);
1126 }
static void updateVariablePrepassComment(yyscan_t yyscanner, int from, int to)
1127<FVariable>{BS}"=" {
1128 yy_push_state(YY_START,yyscanner);
1129 yyextra->initializer="=";
1130 yyextra->initializerScope = yyextra->initializerArrayScope = 0;
1131 BEGIN(Initialization);
1132 }
1133<FVariable>"\n" { yyextra->currentModifiers = SymbolModifiers();
1134 pop_state(yyscanner); // end variable declaration list
1135 newLine(yyscanner);
1136 yyextra->docBlock.clear();
1137 }
1138<FVariable>";".*"\n" { yyextra->currentModifiers = SymbolModifiers();
1139 pop_state(yyscanner); // end variable declaration list
1140 yyextra->docBlock.clear();
1141 yyextra->inputStringSemi = " \n"+DString(yytext+1);
1142 yyextra->lineNr--;
1143 pushBuffer(yyscanner,yyextra->inputStringSemi);
1144 }
1145<*>";".*"\n" {
1146 if (YY_START == FVariable) REJECT; // Just be on the safe side
1147 if (YY_START == String) REJECT; // ";" ignored in strings
1148 if (YY_START == StrIgnore) REJECT; // ";" ignored in regular yyextra->comments
1149 if (YY_START == DocBlock) REJECT; // ";" ignored in documentation blocks
1150 yyextra->inputStringSemi = " \n"+DString(yytext+1);
1151 yyextra->lineNr--;
1152 pushBuffer(yyscanner,yyextra->inputStringSemi);
1153 }
1154
1155<Initialization,ArrayInitializer>"[" |
1156<Initialization,ArrayInitializer>"(/" { yyextra->initializer+=yytext;
1157 yyextra->initializerArrayScope++;
1158 BEGIN(ArrayInitializer); // initializer may contain comma
1159 }
1160<ArrayInitializer>"]" |
1161<ArrayInitializer>"/)" { yyextra->initializer+=yytext;
1162 yyextra->initializerArrayScope--;
1163 if (yyextra->initializerArrayScope<=0)
1164 {
1165 yyextra->initializerArrayScope = 0; // just in case
1166 BEGIN(Initialization);
1167 }
1168 }
1169<ArrayInitializer>. { yyextra->initializer+=yytext; }
1170<Initialization>"(" { yyextra->initializerScope++;
1171 yyextra->initializer+=yytext;
1172 }
1173<Initialization>")" { yyextra->initializerScope--;
1174 yyextra->initializer+=yytext;
1175 }
1176<Initialization>{COMMA} { if (yyextra->initializerScope == 0)
1177 {
1178 updateVariablePrepassComment(yyscanner,yyextra->colNr-(int)yyleng, yyextra->colNr);
1179 pop_state(yyscanner); // end initialization
1180 if (yyextra->last_enum)
1181 {
1182 yyextra->last_enum->initializer.str(yyextra->initializer.str());
1183 }
1184 else
1185 {
1186 if (yyextra->vtype == V_VARIABLE) yyextra->last_entry->initializer.str(yyextra->initializer.str());
1187 }
1188 }
1189 else
1190 {
1191 yyextra->initializer+=", ";
1192 }
1193 }
1194<Initialization>"\n"|"!" { //|
1195 pop_state(yyscanner); // end initialization
1196 if (yyextra->last_enum)
1197 {
1198 yyextra->last_enum->initializer.str(yyextra->initializer.str());
1199 }
1200 else
1201 {
1202 if (yyextra->vtype == V_VARIABLE) yyextra->last_entry->initializer.str(yyextra->initializer.str());
1203 }
1204 yyextra->colNr -= 1;
1205 unput(*yytext);
1206 }
1207<Initialization>. { yyextra->initializer+=yytext; }
1208
1209<*>{BS}"enum"{BS}","{BS}"bind"{BS}"("{BS}"c"{BS}")"{BS} {
1210 if (YY_START == Start)
1211 {
1212 addModule(yyscanner);
1213 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
1214 yy_push_state(ModuleBody,yyscanner); //anon program
1215 }
1216
1217 yy_push_state(FEnum,yyscanner);
1218 yyextra->current->protection = yyextra->defaultProtection;
1219 yyextra->typeProtection = yyextra->defaultProtection;
1220 yyextra->typeMode = true;
1221
1222 yyextra->current->spec.setStruct(true);
1223 yyextra->current->name.clear();
1224 yyextra->current->args.clear();
1225 yyextra->current->name.sprintf("@%d",yyextra->anonCount++);
1226
1227 yyextra->current->section = EntryType::makeEnum();
1228 yyextra->current->fileName = yyextra->fileName;
1229 yyextra->current->startLine = yyextra->lineNr;
1230 yyextra->current->bodyLine = yyextra->lineNr;
1231 if ((yyextra->current_root) &&
1232 (yyextra->current_root->section.isClass() ||
1233 yyextra->current_root->section.isNamespace()))
1234 {
1235 yyextra->current->name = yyextra->current_root->name + "::" + yyextra->current->name;
1236 }
1237
1238 addCurrentEntry(yyscanner,true);
1239 startScope(yyscanner,yyextra->last_entry.get());
1240 BEGIN( FEnum ) ;
1241 }
1242<FEnum>"end"{BS}"enum" {
1243 yyextra->last_entry->parent()->endBodyLine = yyextra->lineNr;
1244 if (!endScope(yyscanner,yyextra->current_root))
1245 {
1246 yyterminate();
1247 }
1248 yyextra->typeMode = false;
1249 pop_state(yyscanner);
1250 }
1251 /*------ fortran subroutine/function handling ------------------------------------------------------------*/
1252 /* Start is initial condition */
1253
1254<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}({PREFIX}{BS_})?/{SUBPROG}{BS_} {
1255 if (yyextra->ifType == IF_ABSTRACT || yyextra->ifType == IF_SPECIFIC)
1256 {
1257 addInterface(yyscanner,"$interface$", yyextra->ifType);
1258 startScope(yyscanner,yyextra->last_entry.get());
1259 }
1260
1261 // TYPE_SPEC is for old function style function result
1262 yyextra->current->type = DString(yytext).stripWhiteSpace().lower();
1263 yy_push_state(SubprogPrefix,yyscanner);
1264 }
1265
1266<SubprogPrefix>{BS}{SUBPROG}{BS_} {
1267 // Fortran subroutine or function found
1268 yyextra->vtype = V_IGNORE;
1269 DString result=yytext;
1270 result=result.stripWhiteSpace();
1271 addSubprogram(yyscanner,result);
1272 BEGIN(Subprog);
1273 yyextra->current->bodyLine = yyextra->lineNr + yyextra->lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
1274 yyextra->current->startLine = yyextra->lineNr;
1275 }
static void addSubprogram(yyscan_t yyscanner, const DString &text)
1276
1277<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} {
1278 // Fortran subroutine or function found
1279 yyextra->vtype = V_IGNORE;
1280 if (yyextra->ifType == IF_ABSTRACT || yyextra->ifType == IF_SPECIFIC)
1281 {
1282 addInterface(yyscanner,"$interface$", yyextra->ifType);
1283 startScope(yyscanner,yyextra->last_entry.get());
1284 }
1285
1286 DString result = DString(yytext).stripWhiteSpace();
1287 addSubprogram(yyscanner,result);
1288 yy_push_state(Subprog,yyscanner);
1289 yyextra->current->bodyLine = yyextra->lineNr + yyextra->lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
1290 yyextra->current->startLine = yyextra->lineNr;
1291 }
1292
1293<Subprog>{BS} { /* ignore white space */ }
1294<Subprog>{ID} { yyextra->current->name = yytext;
1295 //cout << "1a==========> got " << yyextra->current->type << " " << yytext << " " << yyextra->lineNr << endl;
1296 DString returnName = yyextra->current->name.lower();
1297 /* if type is part of a module, mod name is necessary for output */
1298 if ((yyextra->current_root) &&
1299 (yyextra->current_root->section.isClass() ||
1300 yyextra->current_root->section.isNamespace()))
1301 {
1302 yyextra->current->name= yyextra->current_root->name + "::" + yyextra->current->name;
1303 }
1304 yyextra->modifiers[yyextra->current_root][yyextra->current->name.lower().str()].returnName = std::move(returnName);
1305
1306 if (yyextra->ifType == IF_ABSTRACT || yyextra->ifType == IF_SPECIFIC)
1307 {
1308 yyextra->current_root->name = substitute(
1309 yyextra->current_root->name, "$interface$", DString(yytext).lower());
1310 }
1311
1312 BEGIN(Parameterlist);
1313 }
1314<Parameterlist>"(" { yyextra->current->args = "("; }
1315<Parameterlist>")" {
1316 yyextra->current->args += ")";
1317 yyextra->current->args = removeRedundantWhiteSpace(yyextra->current->args);
1318 addCurrentEntry(yyscanner,true);
1319 startScope(yyscanner,yyextra->last_entry.get());
1320 BEGIN(SubprogBody);
1321 }
DString removeRedundantWhiteSpace(const DString &s)
Definition util.cpp:426
1322<Parameterlist>{COMMA}|{BS} { yyextra->current->args += yytext;
1323 const CommentInPrepass *c = locatePrepassComment(yyscanner,yyextra->colNr-(int)yyleng, yyextra->colNr);
1324 if (c)
1325 {
1326 if (!yyextra->current->argList.empty())
1327 {
1328 yyextra->current->argList.back().docs = c->str;
1329 }
1330 }
1331 }
1332<Parameterlist>{ID} {
1333 //yyextra->current->type not yet available
1334 DString param = DString(yytext).lower();
1335 // std::cout << "3=========> got parameter " << param << "\n";
1336 yyextra->current->args += param;
1337 Argument arg;
1338 arg.name = param;
1339 arg.type = "";
1340 yyextra->current->argList.push_back(arg);
1341 }
1342<Parameterlist>{NOARGS} {
1343 newLine(yyscanner);
1344 //printf("3=========> without parameterlist \n");
1345 addCurrentEntry(yyscanner,true);
1346 startScope(yyscanner,yyextra->last_entry.get());
1347 BEGIN(SubprogBody);
1348 }
1349<SubprogBody>result{BS}\‍({BS}{ID} {
1350 if (yyextra->functionLine)
1351 {
1352 DString result= yytext;
1353 result= result.mid(result.find('(')+1);
1354 result= result.stripWhiteSpace();
1355 yyextra->modifiers[yyextra->current_root->parent()][yyextra->current_root->name.lower().str()].returnName = result;
1356 }
1357 //cout << "=====> got result " << result << endl;
1358 }
1359
1360 /*---- documentation yyextra->comments --------------------------------------------------------------------*/
1361
1362<FVariable,SubprogBody,ModuleBody,TypedefBody,TypedefBodyContains>"!<" { /* backward docu comment */
1363 if (yyextra->vtype != V_IGNORE)
1364 {
1365 yyextra->current->docLine = yyextra->lineNr;
1366 yyextra->docBlockJavaStyle = false;
1367 yyextra->docBlock.clear();
1368 yyextra->docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1369 startCommentBlock(yyscanner,false);
1370 yy_push_state(DocBackLine,yyscanner);
1371 }
1372 else
1373 {
1374 /* handle out of place !< comment as a normal comment */
1375 if (YY_START == String)
1376 {
1377 yyextra->colNr -= (int)yyleng;
1378 REJECT;
1379 } // "!" is ignored in strings
1380 // skip comment line (without docu yyextra->comments "!>" "!<" )
1381 /* ignore further "!" and ignore yyextra->comments in Strings */
1382 if ((YY_START != StrIgnore) && (YY_START != String))
1383 {
1384 yy_push_state(YY_START,yyscanner);
1385 BEGIN(StrIgnore);
1386 yyextra->debugStr="*!";
1387 }
1388 }
1389 }
static void startCommentBlock(yyscan_t yyscanner, bool)
1390<DocBackLine>.* { // contents of yyextra->current comment line
1391 yyextra->docBlock+=yytext;
1392 }
1393<DocBackLine>"\n"{BS}"!"("<"|"!"+) { // comment block (next line is also comment line)
1394 yyextra->docBlock+="\n"; // \n is necessary for lists
1395 newLine(yyscanner);
1396 }
1397<DocBackLine>"\n" { // comment block ends at the end of this line
1398 //cout <<"3=========> comment block : "<< yyextra->docBlock << endl;
1399 yyextra->colNr -= 1;
1400 unput(*yytext);
1401 if (yyextra->vtype == V_VARIABLE)
1402 {
1403 std::shared_ptr<Entry> tmp_entry = yyextra->current;
1404 // temporarily switch to the previous entry
1405 if (yyextra->last_enum)
1406 {
1407 yyextra->current = yyextra->last_enum;
1408 }
1409 else
1410 {
1411 yyextra->current = yyextra->last_entry;
1412 }
1413 handleCommentBlock(yyscanner,stripIndentation(yyextra->docBlock),true);
1414 // switch back
1415 yyextra->current = std::move(tmp_entry);
1416 }
1417 else if (yyextra->vtype == V_PARAMETER)
1418 {
1419 subrHandleCommentBlock(yyscanner,yyextra->docBlock,true);
1420 }
1421 else if (yyextra->vtype == V_RESULT)
1422 {
1423 subrHandleCommentBlockResult(yyscanner,yyextra->docBlock,true);
1424 }
1425 pop_state(yyscanner);
1426 yyextra->docBlock.clear();
1427 }
1428
1429<Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains,FEnum>^{BS} {
1430 yyextra->curIndent = computeIndent(yytext);
1431 }
static int computeIndent(const char *s)
1432<Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains,FEnum>"!>" {
1433 yy_push_state(YY_START,yyscanner);
1434 yyextra->current->docLine = yyextra->lineNr;
1435 yyextra->docBlockJavaStyle = false;
1436 if (YY_START==SubprogBody) yyextra->docBlockInBody = true;
1437 yyextra->docBlock.clear();
1438 yyextra->docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1439 startCommentBlock(yyscanner,false);
1440 BEGIN(DocBlock);
1441 //cout << "start DocBlock " << endl;
1442 }
1443
1444
1445<DocBlock>({CMD}{CMD}){ID}/[^a-z_A-Z0-9] { // escaped command
1446 yyextra->docBlock += yytext;
1447 }
1448<DocBlock>{CMD}("f$"|"f["|"f{"|"f(") {
1449 yyextra->docBlock += yytext;
1450 yyextra->docBlockName=&yytext[1];
1451 if (yyextra->docBlockName.at(1)=='[')
1452 {
1453 yyextra->docBlockName.at(1)=']';
1454 }
1455 if (yyextra->docBlockName.at(1)=='{')
1456 {
1457 yyextra->docBlockName.at(1)='}';
1458 }
1459 if (yyextra->docBlockName.at(1)=='(')
1460 {
1461 yyextra->docBlockName.at(1)=')';
1462 }
1463 yyextra->fencedSize=0;
1464 pushBlockState(yyscanner,yytext);
1465 BEGIN(DocCopyBlock);
1466 }
1467<DocBlock>{CMD}"ifile"{B}+"\""[^\n\"]+"\"" {
1468 yyextra->fileName = &yytext[6];
1469 yyextra->fileName = yyextra->fileName.stripWhiteSpace();
1470 yyextra->fileName = yyextra->fileName.mid(1,yyextra->fileName.length()-2);
1471 yyextra->docBlock += yytext;
1472 }
1473<DocBlock>{CMD}"ifile"{B}+{FILEMASK} {
1474 yyextra->fileName = &yytext[6];
1475 yyextra->fileName = yyextra->fileName.stripWhiteSpace();
1476 yyextra->docBlock += yytext;
1477 }
1478<DocBlock>{CMD}"iline"{LINENR}/[\n\.] |
1479<DocBlock>{CMD}"iline"{LINENR}{B} {
1480 bool ok = false;
1481 int nr = DString(&yytext[6]).toInt(&ok);
1482 if (!ok)
1483 {
1484 warn(yyextra->fileName,yyextra->lineNr,"Invalid line number '{}' for iline command",yytext);
1485 }
1486 else
1487 {
1488 yyextra->lineNr = nr;
1489 }
1490 yyextra->docBlock += yytext;
1491 }
int toInt(bool *ok=nullptr, int base=10) const
Definition dstring.cpp:191
1492<DocBlock>{B}*"<"{PRE}">" {
1493 yyextra->docBlock += yytext;
1494 yyextra->docBlockName="<pre>";
1495 yyextra->fencedSize=0;
1496 pushBlockState(yyscanner,yytext);
1497 BEGIN(DocCopyBlock);
1498 }
1499<DocBlock>{B}*"<"<CODE>">" {
1500 yyextra->docBlock += yytext;
1501 yyextra->docBlockName="<code>";
1502 yyextra->fencedSize=0;
1503 pushBlockState(yyscanner,yytext);
1504 BEGIN(DocCopyBlock);
1505 }
1506<DocBlock>{CMD}"startuml"/[^a-z_A-Z0-9\-] { // verbatim command
1507 yyextra->docBlock += yytext;
1508 yyextra->docBlockName="uml";
1509 yyextra->fencedSize=0;
1510 pushBlockState(yyscanner,yytext);
1511 BEGIN(DocCopyBlock);
1512 }
1513<DocBlock>{CMD}("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"manonly"|"rtfonly"|"docbookonly"|"dot"|"msc"|"mermaid"|"code")/[^a-z_A-Z0-9\-] { // verbatim command
1514 yyextra->docBlock += yytext;
1515 yyextra->docBlockName=&yytext[1];
1516 yyextra->fencedSize=0;
1517 pushBlockState(yyscanner,yytext);
1518 BEGIN(DocCopyBlock);
1519 }
1520<DocBlock>"~~~"[~]* {
1521 DString pat = yytext;
1522 yyextra->docBlock += pat;
1523 yyextra->docBlockName="~~~";
1524 yyextra->fencedSize=pat.length();
1525 pushBlockState(yyscanner,yytext);
1526 BEGIN(DocCopyBlock);
1527 }
1528<DocBlock>"```"[`]*/(".")?[a-zA-Z0-9#_-]+ |
1529<DocBlock>"```"[`]*/"{"[^}]+"}" |
1530<DocBlock>"```"[`]* {
1531 DString pat = yytext;
1532 yyextra->docBlock += pat;
1533 yyextra->docBlockName="```";
1534 yyextra->fencedSize=pat.length();
1535 pushBlockState(yyscanner,yytext);
1536 BEGIN(DocCopyBlock);
1537 }
1538<DocBlock>"\\ilinebr "{BS} {
1539 DString indent;
1540 int extraSpaces = std::max(0,static_cast<int>(yyleng-9-yyextra->curIndent-2));
1541 indent.fill(' ',extraSpaces);
1542 //printf("extraSpaces=%d\n",extraSpaces);
1543 yyextra->docBlock += "\\ilinebr ";
1544 yyextra->docBlock += indent;
1545 }
DString fill(char c, size_t len)
Fills a string with a predefined character.
Definition dstring.h:278
1546
1547<DocBlock>[^@*`~\/\\\n]+ { // any character that isn't special
1548 yyextra->docBlock += yytext;
1549 }
1550<DocBlock>"\n"{BS}"!"(">"|"!"+) { // comment block (next line is also comment line)
1551 yyextra->docBlock+="\n"; // \n is necessary for lists
1552 newLine(yyscanner);
1553 }
1554<DocBlock>"\n" { // comment block ends at the end of this line
1555 //cout <<"3=========> comment block : "<< yyextra->docBlock << endl;
1556 yyextra->colNr -= 1;
1557 unput(*yytext);
1558 handleCommentBlock(yyscanner,stripIndentation(yyextra->docBlock),true);
1559 pop_state(yyscanner);
1560 }
1561<DocBlock>. { // command block
1562 yyextra->docBlock += *yytext;
1563 }
1564
1565 /* ---- Copy verbatim sections ------ */
1566
1567<DocCopyBlock>"</"{PRE}">" { // end of a <pre> block
1568 yyextra->docBlock += yytext;
1569 if (yyextra->docBlockName=="<pre>")
1570 {
1571 yyextra->docBlockName="";
1572 popBlockState(yyscanner);
1573 BEGIN(DocBlock);
1574 }
1575 }
1576<DocCopyBlock>"</"{CODE}">" { // end of a <code> block
1577 yyextra->docBlock += yytext;
1578 if (yyextra->docBlockName=="<code>")
1579 {
1580 yyextra->docBlockName="";
1581 popBlockState(yyscanner);
1582 BEGIN(DocBlock);
1583 }
1584 }
1585<DocCopyBlock>{CMD}("f$"|"f]"|"f}"|"f)") {
1586 yyextra->docBlock += yytext;
1587 if (yyextra->docBlockName==&yytext[1])
1588 {
1589 yyextra->docBlockName="";
1590 popBlockState(yyscanner);
1591 BEGIN(DocBlock);
1592 }
1593 }
1594<DocCopyBlock>{CMD}("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endmanonly"|"endrtfonly"|"enddot"|"endmsc"|"endmermaid"|"enduml"|"endcode")/[^a-z_A-Z0-9] { // end of verbatim block
1595 yyextra->docBlock += yytext;
1596 if (&yytext[4]==yyextra->docBlockName)
1597 {
1598 yyextra->docBlockName="";
1599 popBlockState(yyscanner);
1600 BEGIN(DocBlock);
1601 }
1602 }
1603
1604<DocCopyBlock>^{B}*{COMM} { // start of a comment line, just ingnore the comment indicator and leading whitespace
1605 }
1606<DocCopyBlock>"~~~"[~]* {
1607 DString pat = yytext;
1608 yyextra->docBlock += pat;
1609 if (yyextra->docBlockName == "~~~" && yyextra->fencedSize==pat.length())
1610 {
1611 popBlockState(yyscanner);
1612 BEGIN(DocBlock);
1613 }
1614 }
1615<DocCopyBlock>"```"[`]* {
1616 DString pat = yytext;
1617 yyextra->docBlock += pat;
1618 if (yyextra->docBlockName == "```" && yyextra->fencedSize==pat.length())
1619 {
1620 popBlockState(yyscanner);
1621 BEGIN(DocBlock);
1622 }
1623 }
1624
1625<DocCopyBlock>[^<@/\*\‍]!`~"\$\\\n]+ { // any character that is not special
1626 yyextra->docBlock += yytext;
1627 }
1628<DocCopyBlock>\n { // newline
1629 yyextra->docBlock += *yytext;
1630 newLine(yyscanner);
1631 }
1632<DocCopyBlock>. { // any other character
1633 yyextra->docBlock += *yytext;
1634 }
1635
1636 /*-----Prototype parsing -------------------------------------------------------------------------*/
1637<Prototype>{BS}{SUBPROG}{BS_} {
1638 BEGIN(PrototypeSubprog);
1639 }
1640<Prototype,PrototypeSubprog>{BS}{SCOPENAME}?{BS}{ID} {
1641 yyextra->current->name = DString(yytext).lower();
1642 yyextra->current->name.stripWhiteSpace();
1643 BEGIN(PrototypeArgs);
1644 }
1645<PrototypeArgs>{
1646"("|")"|","|{BS_} { yyextra->current->args += yytext; }
1647{ID} { yyextra->current->args += yytext;
1648 Argument a;
1649 a.name = DString(yytext).lower();
1650 yyextra->current->argList.push_back(a);
1651 }
1652}
1653
1654 /*------------------------------------------------------------------------------------------------*/
1655
1656<*>"\n" {
1657 newLine(yyscanner);
1658 //if (yyextra->debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << yyextra->debugStr << " state: " <<YY_START << endl;
1659 yyextra->debugStr="";
1660 }
1661
1662
1663 /*---- error: EOF in wrong state --------------------------------------------------------------------*/
1664
1665<*><<EOF>> {
1666 if (yyextra->parsingPrototype)
1667 {
1668 yyterminate();
1669 }
1670 else if ( yyextra->includeStackPtr <= 0 )
1671 {
1672 if (YY_START!=INITIAL && YY_START!=Start)
1673 {
1674 DBG_CTX((stderr,"==== Error: EOF reached in wrong state (end missing)"));
1675 scanner_abort(yyscanner);
1676 }
1677 yyterminate();
1678 }
1679 else
1680 {
1681 popBuffer(yyscanner);
1682 }
1683 }
static void popBuffer(yyscan_t yyscanner)
1684<*>{LOG_OPER} { // Fortran logical comparison keywords
1685 }
1686<*>. {
1687 //yyextra->debugStr+=yytext;
1688 //printf("I:%c\n", *yytext);
1689 } // ignore remaining text
1690
1691 /**********************************************************************************/
1692 /**********************************************************************************/
1693 /**********************************************************************************/
1694%%

◆ yyread()

int yyread ( yyscan_t yyscanner,
char * buf,
int max_size )
static

Definition at line 2926 of file fortranscanner.l.

2927{
2928 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2929 int c=0;
2930 while ( c < max_size && yyextra->inputString[yyextra->inputPosition] )
2931 {
2932 *buf = yyextra->inputString[yyextra->inputPosition++] ;
2933 c++; buf++;
2934 }
2935 return c;
2936}

Variable Documentation

◆ directionParam

const char* directionParam[]
static
Initial value:
=
{
"", "[in]", "[out]", "[in,out]"
}

Definition at line 142 of file fortranscanner.l.

Referenced by subrHandleCommentBlock().

◆ directionStrs

const char* directionStrs[]
static
Initial value:
=
{
"", "intent(in)", "intent(out)", "intent(inout)"
}

Definition at line 138 of file fortranscanner.l.

Referenced by applyModifiers().