Doxygen
Loading...
Searching...
No Matches
fortranscanner.l File Reference
#include <stdint.h>
#include <map>
#include <vector>
#include <stack>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include "fortranscanner.h"
#include "entry.h"
#include "message.h"
#include "config.h"
#include "doxygen.h"
#include "util.h"
#include "defargs.h"
#include "language.h"
#include "commentscan.h"
#include "pre.h"
#include "arguments.h"
#include "debug.h"
#include "markdown.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 82 of file fortranscanner.l.

◆ INVALID_ENTRY

#define INVALID_ENTRY   ((Entry*)0x8)

Definition at line 274 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 at line 268 of file fortranscanner.l.

◆ YY_NO_INPUT

#define YY_NO_INPUT   1

Definition at line 84 of file fortranscanner.l.

◆ YY_NO_UNISTD_H

#define YY_NO_UNISTD_H   1

Definition at line 85 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 273 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 88 of file fortranscanner.l.

88{ IF_NONE, IF_SPECIFIC, IF_GENERIC, IF_ABSTRACT };

◆ ScanVar

enum ScanVar
Enumerator
V_IGNORE 
V_VARIABLE 
V_PARAMETER 
V_RESULT 

Definition at line 87 of file fortranscanner.l.

87{ 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 2985 of file fortranscanner.l.

2986{
2987 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2988 if (case_insens) yyextra->current->name = yyextra->current->name.lower();
2989 //printf("===Adding entry %s to %s\n", qPrint(yyextra->current->name), qPrint(yyextra->current_root->name));
2990 yyextra->last_entry = yyextra->current;
2991 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
2992 initEntry(yyscanner);
static void initEntry(yyscan_t yyscanner)
2993}

References addCurrentEntry(), and initEntry().

Referenced by addCurrentEntry(), 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 3059 of file fortranscanner.l.

3060{
3061 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3062 if (YY_START == Start)
3063 {
3064 addModule(yyscanner);
3065 pushBlockState(yyscanner,DString(yytext)+" (anonymous program)");
3066 yy_push_state(ModuleBody,yyscanner); //anon program
3067 }
DString()=default
static void addModule(yyscan_t yyscanner, const DString &name=DString(), bool isModule=false)
static void pushBlockState(yyscan_t yyscanner, const DString &text)
3068
3069 yyextra->current->section = EntryType::makeClass(); // was EntryType::Interface;
3070 yyextra->current->spec = TypeSpecifier().setInterface(true);
3071 yyextra->current->name = name;
constexpr TypeSpecifier() noexcept
Definition types.h:696
3072
3073 switch (type)
3074 {
3075 case IF_ABSTRACT:
3076 yyextra->current->type = "abstract";
3077 break;
@ IF_ABSTRACT
3078
3079 case IF_GENERIC:
3080 yyextra->current->type = "generic";
3081 break;
@ IF_GENERIC
3082
3083 case IF_SPECIFIC:
3084 case IF_NONE:
3085 default:
3086 yyextra->current->type = "";
3087 }
@ IF_NONE
@ IF_SPECIFIC
3088
3089 /* if type is part of a module, mod name is necessary for output */
3090 if ((yyextra->current_root) &&
3091 (yyextra->current_root->section.isClass() ||
3092 yyextra->current_root->section.isNamespace()))
3093 {
3094 yyextra->current->name= yyextra->current_root->name + "::" + yyextra->current->name;
3095 }
3096
3097 yyextra->current->fileName = yyextra->fileName;
3098 yyextra->current->bodyLine = yyextra->lineNr;
3099 yyextra->current->startLine = yyextra->lineNr;
3100 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
3101}

References addCurrentEntry(), addInterface(), addModule(), DString::DString(), IF_ABSTRACT, IF_GENERIC, IF_NONE, IF_SPECIFIC, pushBlockState(), and TypeSpecifier::TypeSpecifier().

Referenced by addInterface().

◆ addModule()

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

Definition at line 2995 of file fortranscanner.l.

2996{
2997 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2998 DBG_CTX((stderr, "0=========> got module %s\n", qPrint(name)));
#define DBG_CTX(x)
Definition code.l:74
const char * qPrint(const char *s)
Definition dstring.h:787
2999
3000 if (isModule)
3001 yyextra->current->section = EntryType::makeNamespace();
3002 else
3003 yyextra->current->section = EntryType::makeFunction();
3004
3005 if (!name.empty())
3006 {
3007 yyextra->current->name = name;
3008 }
3009 else
3010 {
3011 DString fname = yyextra->fileName;
3012 size_t index1 = fname.rfind('/');
3013 size_t index2 = fname.rfind('\\');
3014 size_t index = index1!=DString::npos && index2!=DString::npos ? std::max(index1,index2) :
3015 index1!=DString::npos ? index1 : index2;
3016 if (index!=DString::npos) fname = fname.mid(index+1);
3017 if (yyextra->mainPrograms) fname += "__" + DString().setNum(yyextra->mainPrograms);
3018 yyextra->mainPrograms++;
3019 fname = fname.prepend("__").append("__");
3020 yyextra->current->name = substitute(fname, ".", "_");
3021 }
3022 yyextra->current->type = "program";
3023 yyextra->current->fileName = yyextra->fileName;
3024 yyextra->current->bodyLine = yyextra->lineNr; // used for source reference
3025 yyextra->current->startLine = yyextra->lineNr;
3026 yyextra->current->protection = Protection::Public ;
3027 addCurrentEntry(yyscanner,true);
3028 startScope(yyscanner,yyextra->last_entry.get());
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:88
DString & setNum(short n)
Definition dstring.h:556
size_t rfind(char c, size_t pos=npos) const
Definition dstring.h:248
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:322
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:152
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:182
DString & append(char c)
Definition dstring.h:493
DString & prepend(const char *s)
Definition dstring.h:519
DString substitute(const DString &s, const DString &src, const DString &dst)
substitute all occurrences of src in s by dst
Definition dstring.cpp:481
static void startScope(yyscan_t yyscanner, Entry *scope)
3029}

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

Referenced by addInterface(), and addModule().

◆ addSubprogram()

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

Definition at line 3032 of file fortranscanner.l.

3033{
3034 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3035 DBG_CTX((stderr,"1=========> got subprog, type: %s\n",qPrint(text)));
3036 yyextra->subrCurrent.push_back(yyextra->current);
3037 yyextra->current->section = EntryType::makeFunction();
3038 DString subtype = text; subtype=subtype.lower().stripWhiteSpace();
3039 yyextra->functionLine = subtype.find("function")!=DString::npos;
3040 yyextra->current->type += " " + subtype;
3041 yyextra->current->type = yyextra->current->type.stripWhiteSpace();
3042 if (yyextra->ifType == IF_ABSTRACT)
3043 {
3044 yyextra->current->virt = Specifier::Virtual;
3045 }
3046 yyextra->current->fileName = yyextra->fileName;
3047 yyextra->current->bodyLine = yyextra->lineNr; // used for source reference start of body of routine
3048 yyextra->current->startLine = yyextra->lineNr; // used for source reference start of definition
3049 yyextra->current->args.clear();
3050 yyextra->current->argList.clear();
3051 pushBlockState(yyscanner,text);
3052 yyextra->docBlock.clear();
void clear()
Definition dstring.h:218
DString lower() const
Definition dstring.h:330
size_t find(char c, size_t pos=0) const
Definition dstring.h:243
DString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition dstring.h:341
3053}

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

Referenced by addSubprogram().

◆ applyModifiers() [1/3]

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

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

Definition at line 2621 of file fortranscanner.l.

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

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 2504 of file fortranscanner.l.

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

References SymbolModifiers::allocatable, applyModifiers(), 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(), 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 2627 of file fortranscanner.l.

2628{
2629 ent->type = applyModifiers(ent->type, mdfs);
DString type
member type
Definition entry.h:172
2630
2632 ent->protection = Protection::Public;
2633 else if (mdfs.protection == SymbolModifiers::PRIVATE)
2634 ent->protection = Protection::Private;
Protection protection
class protection
Definition entry.h:179
2635
2636 if (mdfs.nonoverridable)
2637 ent->spec.setFinal(true);
2638 if (mdfs.nopass)
2639 ent->isStatic = true;
2640 if (mdfs.deferred)
2641 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
2642}

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 1718 of file fortranscanner.l.

1719{
1720 int col=0;
1721 int tabSize=Config_getInt(TAB_SIZE);
1722 const char *p=s;
1723 char c = 0;
1724 while ((c=*p++))
1725 {
1726 if (c=='\t') col+=tabSize-(col%tabSize);
1727 else if (c=='\n') col=0;
1728 else col++;
1729 }
1730 return col;
#define Config_getInt(name)
Definition config.h:34
1731}

References computeIndent(), and Config_getInt.

◆ convertFileNameFortranParserCode()

FortranFormat convertFileNameFortranParserCode ( const DString & fn)

Definition at line 2207 of file fortranscanner.l.

2208{
2209 DString ext = getFileNameExtension(fn);
2210 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:4212
2211
2212 if (parserName == "fortranfixed") return FortranFormat::Fixed;
2213 else if (parserName == "fortranfree") return FortranFormat::Free;
2214
2216}

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

Referenced by convertCppComments(), convertFileNameFortranParserCode(), 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 2245 of file fortranscanner.l.

2246{
2247 dest->type = src->type;
2248 dest->fileName = src->fileName;
2249 dest->startLine = src->startLine;
2250 dest->bodyLine = src->bodyLine;
2251 dest->endBodyLine = src->endBodyLine;
2252 dest->args = src->args;
2253 dest->argList = src->argList;
2254 dest->doc = src->doc;
2255 dest->docLine = src->docLine;
2256 dest->docFile = src->docFile;
2257 dest->brief = src->brief;
2258 dest->briefLine= src->briefLine;
2259 dest->briefFile= src->briefFile;
2260}

References copyEntry().

Referenced by copyEntry(), and 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 2664 of file fortranscanner.l.

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

References applyModifiers(), Entry::children(), end(), endScope(), 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 endScope(), and parseMain().

◆ extractBind()

DString extractBind ( const DString & name)
static

remove useless spaces from bind statement

Definition at line 2322 of file fortranscanner.l.

2323{
2324 DString parensPart = extractFromParens(name);
2325 if (parensPart.length() == 1)
2326 {
2327 return "bind(C)";
2328 }
2329 else
2330 {
2331 //strip 'c'
2332 parensPart = parensPart.mid(1).stripWhiteSpace();
2333 // strip ','
2334 parensPart = parensPart.mid(1).stripWhiteSpace();
2335 // name part
2336 parensPart = parensPart.mid(4).stripWhiteSpace();
2337 // = part
2338 parensPart = parensPart.mid(1).stripWhiteSpace();
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition dstring.h:155
static DString extractFromParens(const DString &name)
2339
2340 return "bind(C, name=" + parensPart + ")";
2341 }
2342}

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

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

◆ extractFromParens()

DString extractFromParens ( const DString & name)
static

Extracts string which resides within parentheses of provided string.

Definition at line 2304 of file fortranscanner.l.

2305{
2306 DString extracted = name;
2307 if (size_t start = extracted.find('('); start!=DString::npos)
2308 {
2309 extracted.remove(0, start+1);
2310 }
2311 if (size_t end = extracted.rfind(')'); end!=DString::npos)
2312 {
2313 size_t length = extracted.length();
2314 extracted.remove(end, length);
2315 }
2316 extracted = extracted.stripWhiteSpace();
2317
2318 return extracted;
2319}

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

Referenced by extractBind(), extractFromParens(), 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 2487 of file fortranscanner.l.

2488{
2489 DString cname(name.lower());
2490 for (Argument &arg : subprog->argList)
2491 {
2492 if ((!byTypeName && arg.name.lower() == cname) ||
2493 (byTypeName && arg.type.lower() == cname)
2494 )
2495 {
2496 return &arg;
2497 }
2498 }
2499 return nullptr;
ArgumentList argList
member arguments as a list
Definition entry.h:194
2500}

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

Referenced by endScope(), and findArgument().

◆ getAmpersandAtTheStart()

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

Definition at line 1765 of file fortranscanner.l.

1766{
1767 for(int i=0; i<length; i++)
1768 {
1769 switch(buf[i])
1770 {
1771 case ' ':
1772 case '\t':
1773 break;
1774 case '&':
1775 return i;
1776 default:
1777 return -1;
1778 }
1779 }
1780 return -1;
1781}

References getAmpersandAtTheStart().

Referenced by getAmpersandAtTheStart().

◆ getAmpOrExclAtTheEnd()

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

Definition at line 1784 of file fortranscanner.l.

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

References getAmpOrExclAtTheEnd().

Referenced by getAmpOrExclAtTheEnd(), and prepassFixedForm().

◆ getLexerFILE()

const char * getLexerFILE ( )
inlinestatic

Definition at line 271 of file fortranscanner.l.

271{return __FILE__;}

References getLexerFILE().

◆ getParameter()

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

Get the argument name.

Definition at line 3108 of file fortranscanner.l.

3109{
3110 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3111 // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.empty()?DString("null"):docs)<<"\n";
3112 Argument *ret = nullptr;
3113 for (Argument &a:yyextra->current_root->argList)
3114 {
3115 if (a.name.lower()==name.lower())
3116 {
3117 ret=&a;
3118 //printf("parameter found: %s\n",(const char*)name);
3119 break;
3120 }
3121 } // for
3122 return ret;
3123}

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

Referenced by getParameter(), and updateVariablePrepassComment().

◆ handleCommentBlock()

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

Definition at line 3143 of file fortranscanner.l.

3144{
3145 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3146 bool hideInBodyDocs = Config_getBool(HIDE_IN_BODY_DOCS);
3147 if (yyextra->docBlockInBody && hideInBodyDocs)
3148 {
3149 yyextra->docBlockInBody = false;
3150 return;
3151 }
3152 DBG_CTX((stderr,"call parseCommentBlock [%s]\n",qPrint(doc)));
3153 int lineNr = brief ? yyextra->current->briefLine : yyextra->current->docLine;
3154 int position=0;
3155 bool needsEntry = false;
3156 Markdown markdown(yyextra->fileName,lineNr);
3157 GuardedSectionStack guards;
3158 DString strippedDoc = stripIndentation(doc);
3159 DString processedDoc = Config_getBool(MARKDOWN_SUPPORT) ? markdown.process(strippedDoc,lineNr) : strippedDoc;
3160 while (yyextra->commentScanner.parseCommentBlock(
3161 yyextra->thisParser,
3162 yyextra->docBlockInBody ? yyextra->subrCurrent.back().get() : yyextra->current.get(),
3163 processedDoc, // text
3164 yyextra->fileName, // file
3165 lineNr,
3166 yyextra->docBlockInBody ? false : brief,
3167 yyextra->docBlockInBody ? false : yyextra->docBlockJavaStyle,
3168 yyextra->docBlockInBody,
3169 yyextra->defaultProtection,
3170 position,
3171 needsEntry,
3172 Config_getBool(MARKDOWN_SUPPORT),
3173 &guards
3174 ))
3175 {
3176 DBG_CTX((stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry));
3177 if (needsEntry) addCurrentEntry(yyscanner,false);
3178 }
3179 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:161
Helper class to process markdown formatted text.
Definition markdown.h:32
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:4685
3180
3181 if (needsEntry) addCurrentEntry(yyscanner,false);
3182 yyextra->docBlockInBody = false;
3183}

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

Referenced by handleCommentBlock(), subrHandleCommentBlock(), and subrHandleCommentBlockResult().

◆ initEntry()

void initEntry ( yyscan_t yyscanner)
static

Definition at line 2956 of file fortranscanner.l.

2957{
2958 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2959 if (yyextra->typeMode)
2960 {
2961 yyextra->current->protection = yyextra->typeProtection;
2962 }
2963 else if (yyextra->current_root && yyextra->current_root->section.isClass() && yyextra->current_root->spec.isInterface())
2964 {
2965 yyextra->current->protection = Protection::Public;
2966 }
2967 else if (yyextra->current_root && yyextra->current_root->section.isFunction())
2968 {
2969 yyextra->current->protection = Protection::Private;
2970 }
2971 else
2972 {
2973 yyextra->current->protection = yyextra->defaultProtection;
2974 }
2975 yyextra->current->mtype = MethodTypes::Method;
2976 yyextra->current->virt = Specifier::Normal;
2977 yyextra->current->isStatic = false;
2978 yyextra->current->lang = SrcLangExt::Fortran;
2979 yyextra->commentScanner.initGroupInfo(yyextra->current.get());
2980}

References initEntry().

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

◆ initParser()

void initParser ( yyscan_t yyscanner)
static

Definition at line 2950 of file fortranscanner.l.

2951{
2952 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2953 yyextra->last_entry.reset();
2954}

References initParser().

Referenced by initParser(), and parseMain().

◆ insertCharacter()

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

Definition at line 1864 of file fortranscanner.l.

1865{
1866 // shift tail by one character
1867 for(int i=length; i>pos; i--)
1868 contents[i]=contents[i-1];
1869 // set the character
1870 contents[pos] = c;
1871}

References insertCharacter().

Referenced by insertCharacter(), and prepassFixedForm().

◆ keyWordsFortranC()

bool keyWordsFortranC ( const char * contents)
static

Definition at line 2135 of file fortranscanner.l.

2136{
2137 static const std::unordered_set<std::string> fortran_C_keywords = {
2138 "character", "call", "close", "common", "continue",
2139 "case", "contains", "cycle", "class", "codimension",
2140 "concurrent", "contiguous", "critical"
2141 };
2142
2143 if (*contents != 'c' && *contents != 'C') return false;
2144
2145 const char *c = contents;
2146 DString keyword;
2147 while (*c && *c != ' ') {keyword += *c; c++;}
2148 keyword = keyword.lower();
2149
2150 return (fortran_C_keywords.find(keyword.str()) != fortran_C_keywords.end());
2151}

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

Referenced by keyWordsFortranC(), and recognizeFixedForm().

◆ locatePrepassComment()

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

Definition at line 1733 of file fortranscanner.l.

1734{
1735 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1736 //printf("Locate %d-%d\n", from, to);
1737 for (const auto &cip : yyextra->comments)
1738 { // todo: optimize
1739 int c = cip.column;
1740 //printf("Candidate %d\n", c);
1741 if (c>=from && c<=to)
1742 {
1743 // comment for previous variable or parameter
1744 return &cip;
1745 }
1746 }
1747 return nullptr;
1748}

References CommentInPrepass::column, and locatePrepassComment().

Referenced by locatePrepassComment(), and updateVariablePrepassComment().

◆ newLine()

void newLine ( yyscan_t yyscanner)
static

Definition at line 1709 of file fortranscanner.l.

1710{
1711 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1712 yyextra->lineNr++;
1713 yyextra->lineNr+=yyextra->lineCountPrepass;
1714 yyextra->lineCountPrepass=0;
1715 yyextra->comments.clear();
1716}

References newLine().

Referenced by newLine().

◆ parseMain()

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

Definition at line 3320 of file fortranscanner.l.

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

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

Referenced by FortranOutlineParser::parseInput(), and parseMain().

◆ pop_state()

void pop_state ( yyscan_t yyscanner)
inlinestatic

Definition at line 3509 of file fortranscanner.l.

3510{
3511 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3512 if ( yyg->yy_start_stack_ptr <= 0 )
3513 warn(yyextra->fileName,yyextra->lineNr,"Unexpected statement '{}'",yytext );
3514 else
3515 yy_pop_state(yyscanner);
#define warn(file, line, fmt,...)
Definition message.h:97
3516}

References pop_state(), and warn.

Referenced by pop_state().

◆ popBlockState()

void popBlockState ( yyscan_t yyscanner)
static

Definition at line 3526 of file fortranscanner.l.

3527{
3528 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3529 if (yyextra->blockStack.empty())
3530 {
3531 warn(yyextra->fileName,yyextra->lineNr,"Internal inconsistency: empty stack while attempting popBlockState");
3532 }
3533 else
3534 {
3535 yyextra->blockStack.pop();
3536 }
3537 if (yyextra->blockStack.empty())
3538 {
3539 yyextra->blockString.clear();
3540 yyextra->blockLineNr=-1;
3541 }
3542 else
3543 {
3544 yyextra->blockString=yyextra->blockStack.top().blockString;
3545 yyextra->blockLineNr=yyextra->blockStack.top().blockLineNr;
3546 }
3547}

References popBlockState(), and warn.

Referenced by popBlockState().

◆ popBuffer()

void popBuffer ( yyscan_t yyscanner)
static

Definition at line 2235 of file fortranscanner.l.

2236{
2237 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2238 DBG_CTX((stderr, "--POP--"));
2239 yyextra->includeStackPtr --;
2240 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
2241 yy_switch_to_buffer( yyextra->includeStack[yyextra->includeStackPtr], yyscanner );
2242}

References DBG_CTX, and popBuffer().

Referenced by FortranOutlineParser::parsePrototype(), and popBuffer().

◆ prepassFixedForm()

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

Definition at line 1875 of file fortranscanner.l.

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

References getAmpOrExclAtTheEnd(), insertCharacter(), and prepassFixedForm().

Referenced by checkContLines(), parseMain(), and prepassFixedForm().

◆ pushBlockState()

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

Definition at line 3518 of file fortranscanner.l.

3519{
3520 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3521 yyextra->blockString = text;
3522 yyextra->blockLineNr = yyextra->lineNr;
3523 yyextra->blockStack.emplace(yyextra->blockString,yyextra->blockLineNr);
3524}

References pushBlockState().

Referenced by addInterface(), addSubprogram(), and pushBlockState().

◆ pushBuffer()

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

Definition at line 2221 of file fortranscanner.l.

2222{
2223 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2224 if (yyextra->includeStackCnt <= yyextra->includeStackPtr)
2225 {
2226 yyextra->includeStackCnt++;
2227 yyextra->includeStack = (YY_BUFFER_STATE *)realloc(yyextra->includeStack, yyextra->includeStackCnt * sizeof(YY_BUFFER_STATE));
2228 }
2229 yyextra->includeStack[yyextra->includeStackPtr++] = YY_CURRENT_BUFFER;
2230 yy_switch_to_buffer(yy_scan_string(buffer.data(),yyscanner),yyscanner);
2231
2232 DBG_CTX((stderr, "--PUSH--%s", qPrint(buffer)));
2233}

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

Referenced by FortranOutlineParser::parsePrototype(), and pushBuffer().

◆ recognizeFixedForm()

bool recognizeFixedForm ( const DString & contents,
FortranFormat format )

Definition at line 2154 of file fortranscanner.l.

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

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

Referenced by convertCppComments(), FortranCodeParser::parseCode(), parseMain(), recognizeFixedForm(), 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 2267 of file fortranscanner.l.

2268{
2269 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2270 if (yyextra->moduleProcedures.empty()) return;
2271
2272 // build up map of available functions
2273 std::map<std::string,std::shared_ptr<Entry>> procMap;
2274 {
2275 for (const auto& cf: current_root->children())
2276 {
2277 if (!cf->section.isFunction())
2278 continue;
2279
2280 // remove scope from name
2281 DString name = cf->name;
2282 {
2283 if (size_t end = name.rfind(':') ; end!=DString::npos) name.remove(0, end+1);
2284 }
2285
2286 procMap.emplace(name.str(), cf);
2287 }
2288 }
2289
2290
2291 // for all module procedures
2292 for (const auto& ce1: yyextra->moduleProcedures)
2293 {
2294 if (procMap.find(ce1->name.str())!=procMap.end())
2295 {
2296 std::shared_ptr<Entry> proc = procMap[ce1->name.str()];
2297 copyEntry(ce1, proc);
2298 }
2299 } // for all interface module procedures
2300 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
2301}

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

Referenced by resolveModuleProcedures().

◆ 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 2791 of file fortranscanner.l.

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

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

Referenced by endScope(), and resolveTypeBoundProcedures().

◆ scanner_abort()

void scanner_abort ( yyscan_t yyscanner)
static

Definition at line 3475 of file fortranscanner.l.

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

References qPrint(), scanner_abort(), and stateToString().

Referenced by endScope(), and scanner_abort().

◆ startCommentBlock()

void startCommentBlock ( yyscan_t yyscanner,
bool brief )
static

Definition at line 3126 of file fortranscanner.l.

3127{
3128 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3129 if (brief)
3130 {
3131 yyextra->current->briefFile = yyextra->fileName;
3132 yyextra->current->briefLine = yyextra->lineNr;
3133 }
3134 else
3135 {
3136 yyextra->current->docFile = yyextra->fileName;
3137 yyextra->current->docLine = yyextra->lineNr;
3138 }
3139}

References startCommentBlock().

Referenced by startCommentBlock().

◆ 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 2648 of file fortranscanner.l.

2649{
2650 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2651 //cout<<"start scope: "<<scope->name<<endl;
2652 yyextra->current_root= scope; /* start substructure */
2653
2654 yyextra->modifiers.emplace(scope, std::map<std::string,SymbolModifiers>());
2655
2656 // create new current with possibly different defaults...
2657 yyextra->current = std::make_shared<Entry>();
2658 initEntry(yyscanner);
2659}

References initEntry(), and startScope().

Referenced by addModule(), parseMain(), and startScope().

◆ stateToString()

const char * stateToString ( int state)
static

References computeIndent(), and stateToString().

◆ 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 3187 of file fortranscanner.l.

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

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

Referenced by subrHandleCommentBlock().

◆ 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 3290 of file fortranscanner.l.

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

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

Referenced by subrHandleCommentBlockResult().

◆ truncatePrepass()

void truncatePrepass ( yyscan_t yyscanner,
int index )
static

Definition at line 1851 of file fortranscanner.l.

1852{
1853 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1854 size_t length = yyextra->inputStringPrepass.length();
1855 for (size_t i=index+1; i<length; i++) {
1856 if (yyextra->inputStringPrepass[i]=='!' && i<length-1 && yyextra->inputStringPrepass[i+1]=='<') { // save comment
1857 yyextra->comments.emplace_back(index, yyextra->inputStringPrepass.right(length-i-2));
1858 }
1859 }
1860 yyextra->inputStringPrepass.resize(index);
1861}

References truncatePrepass().

Referenced by truncatePrepass().

◆ updateVariablePrepassComment()

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

Definition at line 1750 of file fortranscanner.l.

1751{
1752 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1753 const CommentInPrepass *c = locatePrepassComment(yyscanner,from, to);
1754 if (c && yyextra->vtype == V_VARIABLE)
1755 {
1756 yyextra->last_entry->brief = c->str;
1757 }
1758 else if (c && yyextra->vtype == V_PARAMETER)
1759 {
1760 Argument *parameter = getParameter(yyscanner,yyextra->argName);
1761 if (parameter) parameter->docs = c->str;
1762 }
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)
1763}

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

Referenced by updateVariablePrepassComment().

◆ yylex()

int yylex ( yyscan_t yyscanner)

fortran parsing states

comment parsing states prototype parsing

Definition at line 379 of file fortranscanner.l.

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

◆ yyread()

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

Definition at line 2938 of file fortranscanner.l.

2939{
2940 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2941 int c=0;
2942 while ( c < max_size && yyextra->inputString[yyextra->inputPosition] )
2943 {
2944 *buf = yyextra->inputString[yyextra->inputPosition++] ;
2945 c++; buf++;
2946 }
2947 return c;
2948}

References yyread().

Variable Documentation

◆ directionParam

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

Definition at line 144 of file fortranscanner.l.

Referenced by subrHandleCommentBlock().

◆ directionStrs

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

Definition at line 140 of file fortranscanner.l.

Referenced by applyModifiers().