40%option never-interactive
41%option case-insensitive
42%option prefix="fortranscannerYY"
44%option extra-type="struct fortranscannerYY_state *"
48#define YY_TYPEDEF_YY_SCANNER_T
63#include <unordered_map>
64#include <unordered_set>
80#define DBG_CTX(x) do { } while(0)
83#define YY_NO_UNISTD_H 1
140 "",
"intent(in)",
"intent(out)",
"intent(inout)"
144 "",
"[in]",
"[out]",
"[in,out]"
216 std::map<Entry*,std::map<std::string,SymbolModifiers> >
modifiers;
249static void copyEntry(std::shared_ptr<Entry> dest,
const std::shared_ptr<Entry> &src);
266#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
271#define YY_USER_ACTION yyextra->colNr+=(int)yyleng;
272#define INVALID_ENTRY ((Entry*)0x8)
This class contains the information about the argument of a function or template.
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Represents an unstructured piece of information, about an entity found in the sources.
Abstract interface for outline parsers.
std::vector< std::shared_ptr< Entry > > EntryList
static int getAmpersandAtTheStart(const char *buf, int length)
static const char * directionParam[]
static DString extractFromParens(const DString &name)
static void resolveModuleProcedures(yyscan_t yyscanner, Entry *current_root)
fill empty interface module procedures with info from corresponding module subprogs
static void newLine(yyscan_t yyscanner)
static void popBlockState(yyscan_t yyscanner)
static void addCurrentEntry(yyscan_t yyscanner, bool case_insens)
adds yyextra->current entry to yyextra->current_root and creates new yyextra->current
static void pushBuffer(yyscan_t yyscanner, const DString &buffer)
static int computeIndent(const char *s)
static void addSubprogram(yyscan_t yyscanner, const DString &text)
static void startCommentBlock(yyscan_t yyscanner, bool)
static void addModule(yyscan_t yyscanner, const DString &name=DString(), bool isModule=false)
static void startScope(yyscan_t yyscanner, Entry *scope)
static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch)
static const CommentInPrepass * locatePrepassComment(yyscan_t yyscanner, int from, int to)
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
static void subrHandleCommentBlockResult(yyscan_t yyscanner, const DString &doc, bool brief)
Handle result description as defined after the declaration of the parameter.
static const char * stateToString(int state)
static void popBuffer(yyscan_t yyscanner)
static void addInterface(yyscan_t yyscanner, DString name, InterfaceType type)
static void copyEntry(std::shared_ptr< Entry > dest, const std::shared_ptr< Entry > &src)
used to copy entry to an interface module procedure
static const char * directionStrs[]
static void scanner_abort(yyscan_t yyscanner)
static void pushBlockState(yyscan_t yyscanner, const DString &text)
static void pop_state(yyscan_t yyscanner)
static void resolveTypeBoundProcedures(Entry *scope)
static DString extractBind(const DString &name)
static void updateVariablePrepassComment(yyscan_t yyscanner, int from, int to)
static Argument * getParameter(yyscan_t yyscanner, const DString &name)
static void subrHandleCommentBlock(yyscan_t yyscanner, const DString &doc, bool brief)
Handle parameter description as defined after the declaration of the parameter.
static bool endScope(yyscan_t yyscanner, Entry *scope, bool isGlobalRoot=false)
static const char * getLexerFILE()
static void handleCommentBlock(yyscan_t yyscanner, const DString &doc, bool brief)
static void truncatePrepass(yyscan_t yyscanner, int index)
static void initEntry(yyscan_t yyscanner)
BlockState(DString str, int lineNr)
Holds yyextra->modifiers (ie attributes) for one symbol (variable, function, etc).
SymbolModifiers & operator|=(const SymbolModifiers &mdfs)
DString type
This is only used with function return value.
DString inputStringPrepass
Input string for prepass of line cont. '&'.
std::map< Entry *, std::map< std::string, SymbolModifiers > > modifiers
Holds program scope->symbol name->symbol modifiers.
YY_BUFFER_STATE * includeStack
std::shared_ptr< Entry > last_enum
OutlineParserInterface * thisParser
SymbolModifiers currentModifiers
Accumulated modifiers of current statement, eg variable declaration.
unsigned int inputPositionPrepass
std::shared_ptr< Entry > global_root
std::vector< CommentInPrepass > comments
DString inputStringSemi
Input string after command separator ';'.
EntryList moduleProcedures
CommentScanner commentScanner
int initializerArrayScope
std::stack< BlockState > blockStack
std::shared_ptr< Entry > last_entry
Protection defaultProtection
Protection typeProtection
int mainPrograms
counter for the number of main programs in this file
std::shared_ptr< Entry > current
std::shared_ptr< Entry > file_root
A bunch of utility functions.
284ID [a-z_A-Z%]+{IDSYM}*
285ID_ [a-z_A-Z%]*{IDSYM}*
286OPERATOR_ID (operator{BS}"("{BS}(\.[a-z_A-Z]+\.|"="|"/="|"//"|"=="|"<"|"<="|">"|">="|"+"|"*"|"**"|"/"|"-"){BS}")")
287SUBPROG (subroutine|function)
291BT_ ([ \t]+|[ \t]*"(")
294ARGS_L1a [^()]*"("[^)]*")"[^)]*
295ARGS_L1 ("("{ARGS_L1a}*")")
296ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
297ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
304NUM_TYPE (complex|integer|logical|real)
305LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
307CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
308TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|ENUMERATOR|{CHAR}|TYPE{ARGS}|CLASS{ARGS}|PROCEDURE{ARGS}?)
310INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
311ATTR_SPEC (EXTERNAL|ALLOCATABLE|DIMENSION{ARGS}|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|NOPASS|PASS{ARGS}?|DEFERRED|NON_OVERRIDABLE|CONTIGUOUS|VOLATILE|VALUE)
312LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}((,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})|(,{BS}NAME{BS}"="{BS}"'"(.*)"'"{BS}))?")"
314ATTR_STMT {ATTR_SPEC}|DIMENSION
315EXTERNAL_STMT (EXTERNAL)
318PREFIX ((NON_)?RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,4}((NON_)?RECURSIVE|IMPURE|PURE|ELEMENTAL)?
319SCOPENAME ({ID}{BS}"::"{BS})*
321LINENR {B}*[1-9][0-9]*
322FILEICHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+=&#@~]
323FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+=&#@~]
324FILECHARS {FILEICHAR}*{FILEECHAR}+
325HFILEMASK {FILEICHAR}*("."{FILEICHAR}+)+{FILECHARS}*
326VFILEMASK {FILECHARS}("."{FILECHARS})*
327FILEMASK {VFILEMASK}|{HFILEMASK}
341%x SubprogBodyContains
355%x TypedefBodyContains
381<Prepass>^{BS}[&]*{BS}!.*\n {
382 yyextra->lineCountPrepass ++;
385 yyextra->lineCountPrepass ++;
388 yyextra->functionLine =
false;
390 DBG_CTX((stderr,
"---%s", yytext));
394 if (indexEnd>=0 && yytext[indexEnd]!=
'&')
401 if (YY_START == Prepass)
405 yyextra->inputStringPrepass+=(
const char*)(yytext+(indexStart+1));
408 pushBuffer(yyscanner,yyextra->inputStringPrepass);
420 if (YY_START != Prepass)
422 yyextra->comments.clear();
423 yyextra->inputStringPrepass=
DString();
424 yy_push_state(Prepass,yyscanner);
427 size_t length = yyextra->inputStringPrepass.length();
430 yyextra->inputStringPrepass+=(
const char*)(yytext+(indexStart+1));
431 yyextra->lineCountPrepass ++;
434 truncatePrepass(yyscanner,
static_cast<int>(length) + indexEnd - indexStart - 1);
441 if (yytext[0]!=yyextra->stringStartSymbol)
443 yyextra->colNr -= (int)yyleng;
446 if (yy_top_state(yyscanner) == Initialization ||
447 yy_top_state(yyscanner) == ArrayInitializer)
449 yyextra->initializer+=yytext;
453<String>[\x80-\xFF]* |
454<String>. {
if (yy_top_state(yyscanner) == Initialization ||
455 yy_top_state(yyscanner) == ArrayInitializer)
457 yyextra->initializer+=yytext;
461 if (YY_START == StrIgnore)
462 { yyextra->colNr -= (int)yyleng;
465 yy_push_state(YY_START,yyscanner);
466 if (yy_top_state(yyscanner) == Initialization ||
467 yy_top_state(yyscanner) == ArrayInitializer)
469 yyextra->initializer+=yytext;
471 yyextra->stringStartSymbol=yytext[0];
477<*>"!"/([^<>\n]|"<ff>"|"<FF>") {
if (YY_START == String || YY_START == DocCopyBlock)
478 { yyextra->colNr -= (int)yyleng;
483 if ((YY_START != StrIgnore) && (YY_START != String))
485 yy_push_state(YY_START,yyscanner);
487 yyextra->debugStr=
"*!";
488 DBG_CTX((stderr,
"start comment %d\n",yyextra->lineNr));
492 DBG_CTX((stderr,
"end comment %d %s\n",yyextra->lineNr,
qPrint(yyextra->debugStr)));
const char * qPrint(const char *s)
494<StrIgnore>[\x80-\xFF]* |
495<StrIgnore>. { yyextra->debugStr+=yytext; }
500<Start,ModuleBody,SubprogBody>"use"{BS_} {
501 if (YY_START == Start)
505 yy_push_state(ModuleBody,yyscanner);
507 yy_push_state(Use,yyscanner);
510 DBG_CTX((stderr,
"using dir %s\n",yytext));
511 yyextra->current->name=yytext;
512 yyextra->current->name=yyextra->current->name.lower();
513 yyextra->current->fileName = yyextra->fileName;
514 yyextra->current->section=EntryType::makeUsingDir();
515 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
516 yyextra->current->lang = SrcLangExt::Fortran;
520 yyextra->useModuleName=yytext;
521 yyextra->useModuleName=yyextra->useModuleName.lower();
523<Use>,{BS}"ONLY" { BEGIN(UseOnly);
527 yyextra->current->name= yyextra->useModuleName+
"::"+yytext;
528 yyextra->current->name=yyextra->current->name.lower();
529 yyextra->current->fileName = yyextra->fileName;
530 yyextra->current->section=EntryType::makeUsingDecl();
531 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
532 yyextra->current->lang = SrcLangExt::Fortran;
541<Start,ModuleBody,SubprogBody>{
542^{BS}interface{IDSYM}+ { }
544 yy_push_state(InterfaceBody,yyscanner);
549^{BS}abstract{BS_}interface { yyextra->ifType =
IF_ABSTRACT;
550 yy_push_state(InterfaceBody,yyscanner);
555^{BS}interface{BS_}{ID}{ARGS}? { yyextra->ifType =
IF_GENERIC;
556 yyextra->current->bodyLine = yyextra->lineNr + yyextra->lineCountPrepass + 1;
557 yy_push_state(InterfaceBody,yyscanner);
563 startScope(yyscanner,yyextra->last_entry.get());
DString mid(size_t index, size_t len=npos) const
DString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
567<InterfaceBody>^{BS}end{BS}interface({BS_}{ID})? {
571 yyextra->last_entry->parent()->endBodyLine = yyextra->lineNr - 1;
580<InterfaceBody>module{BS}procedure { yy_push_state(YY_START,yyscanner);
581 BEGIN(ModuleProcedure);
587 startScope(yyscanner,yyextra->last_entry.get());
590 yyextra->current->section = EntryType::makeFunction();
591 yyextra->current->name = name;
592 yyextra->moduleProcedures.
push_back(yyextra->current);
595<ModuleProcedure>"\n" { yyextra->colNr -= 1;
602<Start>^{BS}{CONTAINS}/({BS}|\n|!|;) {
603 if (YY_START == Start)
606 yy_push_state(ModuleBodyContains,yyscanner);
609<ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!|;) { BEGIN(ModuleBodyContains); }
610<SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!|;) { BEGIN(SubprogBodyContains); }
611<TypedefBody>^{BS}{CONTAINS}/({BS}|\n|!|;) { BEGIN(TypedefBodyContains); }
614<Start>block{BS}data{BS}{ID_} {
616 yy_push_state(BlockData,yyscanner);
617 yyextra->defaultProtection = Protection::Public;
619<Start>module|program{BS_} {
621 if (yytext[0]==
'm' || yytext[0]==
'M')
623 yy_push_state(Module,yyscanner);
627 yy_push_state(Program,yyscanner);
629 yyextra->defaultProtection = Protection::Public;
631<BlockData>^{BS}"end"({BS}(block{BS}data)({BS_}{ID})?)?{BS}/(\n|!|;) {
634 yyextra->defaultProtection = Protection::Public;
637<Start,ModuleBody,ModuleBodyContains>"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!|;) {
639 if (!
endScope(yyscanner,yyextra->current_root))
643 yyextra->defaultProtection = Protection::Public;
644 if (yyextra->global_scope)
648 yy_push_state(Start,yyscanner);
657 yy_push_state(Start,yyscanner);
675<ModuleBody,TypedefBody,TypedefBodyContains>private/{BS}(\n|"!") {
676 yyextra->defaultProtection = Protection::Private;
677 yyextra->current->protection = yyextra->defaultProtection ;
679<ModuleBody,TypedefBody,TypedefBodyContains>public/{BS}(\n|"!") {
680 yyextra->defaultProtection = Protection::Public;
681 yyextra->current->protection = yyextra->defaultProtection ;
686<ModuleBody>^{BS}type{BS}"=" {}
687<Start,ModuleBody>^{BS}type/[^a-z0-9_] {
688 if (YY_START == Start)
692 yy_push_state(ModuleBody,yyscanner);
695 yy_push_state(Typedef,yyscanner);
696 yyextra->current->protection = Protection::Package;
697 yyextra->typeProtection = Protection::Public;
698 yyextra->typeMode =
true;
706 yyextra->current->spec.setAbstractClass(
true);
710 yyextra->current->extends.emplace_back(basename, Protection::Public, Specifier::Normal);
713 yyextra->current->protection = Protection::Public;
716 yyextra->current->protection = Protection::Private;
718{LANGUAGE_BIND_SPEC} {
722 yyextra->current->section = EntryType::makeClass();
723 yyextra->current->spec.setStruct(
true);
724 yyextra->current->name = yytext;
725 yyextra->current->fileName = yyextra->fileName;
726 yyextra->current->bodyLine = yyextra->lineNr;
727 yyextra->current->startLine = yyextra->lineNr;
730 if (yyextra->current_root &&
731 (yyextra->current_root->section.isClass() ||
732 yyextra->current_root->section.isNamespace()))
734 yyextra->current->name = yyextra->current_root->name +
"::" + yyextra->current->name;
738 if( yyextra->current->protection == Protection::Package )
740 yyextra->current->protection = yyextra->defaultProtection;
742 else if( yyextra->current->protection == Protection::Public )
744 yyextra->modifiers[yyextra->current_root][yyextra->current->name.lower().str()] |=
DString(
"public");
746 else if( yyextra->current->protection == Protection::Private )
748 yyextra->modifiers[yyextra->current_root][yyextra->current->name.lower().str()] |=
DString(
"private");
752 startScope(yyscanner,yyextra->last_entry.get());
757<TypedefBodyContains>{
758^{BS}PROCEDURE{ARGS}? {
DString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple internal white...
762 yyextra->current->spec.setFinal(
true);
777 yyextra->modifiers[yyextra->current_root][name.
lower().
str()] |= yyextra->currentModifiers;
778 yyextra->current->section = EntryType::makeFunction();
779 yyextra->current->name = name;
787 yyextra->current->args = name.
lower();
789 yyextra->current->fileName = yyextra->fileName;
790 yyextra->current->bodyLine = yyextra->lineNr;
791 yyextra->current->startLine = yyextra->lineNr;
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
const std::string & str() const
796 size_t i = tmp.
find(
"=>");
802 if (yyextra->last_entry->type ==
"generic")
810 copyEntry(yyextra->current, yyextra->last_entry);
811 yyextra->current->name = yyextra->last_entry->name;
812 yyextra->current->section = EntryType::makeFunction();
821 yyextra->last_entry->args = tmp;
DString & remove(size_t index, size_t len)
size_t find(char c, size_t pos=0) const
DString left(size_t len) const
826 yyextra->docBlock.clear();
831<TypedefBody,TypedefBodyContains>{
832^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!|;) {
833 yyextra->last_entry->parent()->endBodyLine = yyextra->lineNr;
834 if (!
endScope(yyscanner,yyextra->current_root))
838 yyextra->typeMode =
false;
841^{BS}"end"{BS}/(\n|!|;) {
842 warn(yyextra->fileName,yyextra->lineNr,
"Found 'END' instead of 'END TYPE'");
843 yyextra->last_entry->parent()->endBodyLine = yyextra->lineNr;
844 if (!
endScope(yyscanner,yyextra->current_root))
848 yyextra->typeMode =
false;
#define warn(file, line, fmt,...)
855<SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!|;) {
863 endScope(yyscanner,yyextra->current_root);
864 yyextra->last_entry->endBodyLine = yyextra->lineNr - 1;
866 yyextra->current_root->endBodyLine = yyextra->lineNr - 1;
868 if (!
endScope(yyscanner,yyextra->current_root))
872 yyextra->subrCurrent.pop_back();
881<Start,ModuleBody,TypedefBody,SubprogBody,FEnum>{
882^{BS}{TYPE_SPEC}/{SEPARATE} {
883 yyextra->last_enum.reset();
884 if (YY_START == FEnum)
886 yyextra->argType =
"@";
892 yyextra->current->bodyLine = yyextra->lineNr + 1;
893 yyextra->current->endBodyLine = yyextra->lineNr + yyextra->lineCountPrepass;
895 if (YY_START == Start)
899 yy_push_state(ModuleBody,yyscanner);
901 yy_push_state(AttributeList,yyscanner);
903{EXTERNAL_STMT}/({BS}"::"|{BS_}{ID}) {
905 if (YY_START == Start)
909 yy_push_state(ModuleBody,yyscanner);
914 yy_push_state(AttributeList,yyscanner);
916{ATTR_STMT}/{BS_}{ID} |
917{ATTR_STMT}/{BS}"::" {
919 DBG_CTX((stderr,
"5=========> Attribute statement: %s\n", yytext));
920 if (YY_START == Start)
924 yy_push_state(ModuleBody,yyscanner);
929 yy_push_state(YY_START,yyscanner);
930 BEGIN( AttributeList ) ;
933 if (YY_START == Start)
937 yy_push_state(ModuleBody,yyscanner);
945 yy_push_state(ModuleBody,yyscanner);
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...
948^{BS}"type"{BS_}"is"/{BT_} {}
950^{BS}"class"{BS_}"is"/{BT_} {}
951^{BS}"class"{BS_}"default" {}
956{LANGUAGE_BIND_SPEC} {
957 yyextra->currentModifiers |= yytext;
961 char chr = yytext[(int)yyleng-1];
964 yyextra->colNr -= (int)yyleng;
972 unput(yytext[(
int)yyleng-1]);
973 yyextra->currentModifiers |= (tmp);
size_t length() const
Returns the length of the string, not counting the 0-terminator.
bool isId(char c)
Returns true if c is a valid character for an identifier.
988<FVariable>{OPERATOR_ID} {
992 int currentState = YY_START;
994 int outerState = YY_START;
995 yy_push_state(currentState,yyscanner);
996 if( outerState == Start || outerState == ModuleBody )
998 if ((yyextra->current_root) &&
999 (yyextra->current_root->section.isClass() ||
1000 yyextra->current_root->section.isNamespace()))
1002 name = yyextra->current_root->name +
"::" + name;
1006 yyextra->modifiers[yyextra->current_root][name.
str()] |= yyextra->currentModifiers;
1012 name = name.
lower();
1014 if ((yyextra->current_root) && yyextra->current_root->section.isNamespace())
1016 name = yyextra->current_root->name +
"::" + name;
1019 yyextra->modifiers[yyextra->current_root][name.
lower().
str()] |= yyextra->currentModifiers;
1020 yyextra->argName= name;
1023 if (!yyextra->argType.empty() && !yyextra->current_root->section.isFunction())
1026 yyextra->current->section = EntryType::makeVariable();
1027 yyextra->current->name = yyextra->argName;
1028 yyextra->current->type = yyextra->argType;
1029 yyextra->current->fileName = yyextra->fileName;
1030 yyextra->current->bodyLine = yyextra->lineNr;
1031 yyextra->current->startLine = yyextra->lineNr;
1032 if (yyextra->argType ==
"@")
1034 yyextra->current_root->copyToSubEntry(yyextra->current);
1036 yyextra->last_enum = yyextra->current;
1037 yyextra->current_root->parent()->moveToSubEntryAndRefresh(yyextra->current);
1045 else if (!yyextra->argType.empty())
1052 if (!yyextra->docBlock.empty())
1060 yyextra->modifiers[yyextra->current_root][name.
lower().
str()].type = yyextra->argType;
1064 if ((yyextra->current_root->name.lower() == yyextra->argName.lower()) ||
1065 (yyextra->modifiers[yyextra->current_root->parent()][yyextra->current_root->name.lower().str()].returnName.lower() == yyextra->argName.lower()))
1067 size_t strt = yyextra->current_root->type.find(
"function");
1076 if ((yyextra->current_root->type.length() - strt - strlen(
"function"))!= 0)
1078 rght = yyextra->current_root->type.
right(yyextra->current_root->type.length() - strt - (
int)strlen(
"function")).
stripWhiteSpace();
1080 yyextra->current_root->type = lft;
1083 if (yyextra->current_root->type.length() > 0) yyextra->current_root->type +=
" ";
1084 yyextra->current_root->type += rght;
1086 if (yyextra->argType.stripWhiteSpace().length() > 0)
1088 if (yyextra->current_root->type.length() > 0) yyextra->current_root->type +=
" ";
1089 yyextra->current_root->type += yyextra->argType.stripWhiteSpace();
1091 if (yyextra->current_root->type.length() > 0) yyextra->current_root->type +=
" ";
1092 yyextra->current_root->type +=
"function";
1093 if (!yyextra->docBlock.empty())
1100 yyextra->current_root->type +=
" " + yyextra->argType.stripWhiteSpace();
1102 yyextra->current_root->type = yyextra->current_root->type.
stripWhiteSpace();
1103 yyextra->modifiers[yyextra->current_root][name.
lower().
str()].type = yyextra->current_root->type;
1107 yyextra->modifiers[yyextra->current_root][name.
lower().
str()].type = yyextra->argType;
1113 yyextra->current->doc.clear();
1114 yyextra->current->brief.clear();
DString right(size_t len) const
1118 DString name(yyextra->argName);
1121 yyextra->modifiers[yyextra->current_root][name.
lower().
str()] |= attr;
1128 yy_push_state(YY_START,yyscanner);
1129 yyextra->initializer=
"=";
1130 yyextra->initializerScope = yyextra->initializerArrayScope = 0;
1131 BEGIN(Initialization);
1136 yyextra->docBlock.clear();
1140 yyextra->docBlock.clear();
1141 yyextra->inputStringSemi =
" \n"+
DString(yytext+1);
1143 pushBuffer(yyscanner,yyextra->inputStringSemi);
1146 if (YY_START == FVariable) REJECT;
1147 if (YY_START == String) REJECT;
1148 if (YY_START == StrIgnore) REJECT;
1149 if (YY_START == DocBlock) REJECT;
1150 yyextra->inputStringSemi =
" \n"+
DString(yytext+1);
1152 pushBuffer(yyscanner,yyextra->inputStringSemi);
1155<Initialization,ArrayInitializer>"[" |
1156<Initialization,ArrayInitializer>"(/" { yyextra->initializer+=yytext;
1157 yyextra->initializerArrayScope++;
1158 BEGIN(ArrayInitializer);
1160<ArrayInitializer>"]" |
1161<ArrayInitializer>"/)" { yyextra->initializer+=yytext;
1162 yyextra->initializerArrayScope--;
1163 if (yyextra->initializerArrayScope<=0)
1165 yyextra->initializerArrayScope = 0;
1166 BEGIN(Initialization);
1169<ArrayInitializer>. { yyextra->initializer+=yytext; }
1170<Initialization>"(" { yyextra->initializerScope++;
1171 yyextra->initializer+=yytext;
1173<Initialization>")" { yyextra->initializerScope--;
1174 yyextra->initializer+=yytext;
1176<Initialization>{COMMA} {
if (yyextra->initializerScope == 0)
1180 if (yyextra->last_enum)
1182 yyextra->last_enum->initializer.str(yyextra->initializer.str());
1186 if (yyextra->vtype ==
V_VARIABLE) yyextra->last_entry->initializer.str(yyextra->initializer.str());
1191 yyextra->initializer+=
", ";
1194<Initialization>"\n"|"!" {
1196 if (yyextra->last_enum)
1198 yyextra->last_enum->initializer.str(yyextra->initializer.str());
1202 if (yyextra->vtype ==
V_VARIABLE) yyextra->last_entry->initializer.str(yyextra->initializer.str());
1204 yyextra->colNr -= 1;
1207<Initialization>. { yyextra->initializer+=yytext; }
1209<*>{BS}"enum"{BS}","{BS}"bind"{BS}"("{BS}"c"{BS}")"{BS} {
1210 if (YY_START == Start)
1214 yy_push_state(ModuleBody,yyscanner);
1217 yy_push_state(FEnum,yyscanner);
1218 yyextra->current->protection = yyextra->defaultProtection;
1219 yyextra->typeProtection = yyextra->defaultProtection;
1220 yyextra->typeMode =
true;
1222 yyextra->current->spec.setStruct(
true);
1223 yyextra->current->name.clear();
1224 yyextra->current->args.clear();
1225 yyextra->current->name.sprintf(
"@%d",yyextra->anonCount++);
1227 yyextra->current->section = EntryType::makeEnum();
1228 yyextra->current->fileName = yyextra->fileName;
1229 yyextra->current->startLine = yyextra->lineNr;
1230 yyextra->current->bodyLine = yyextra->lineNr;
1231 if ((yyextra->current_root) &&
1232 (yyextra->current_root->section.isClass() ||
1233 yyextra->current_root->section.isNamespace()))
1235 yyextra->current->name = yyextra->current_root->name +
"::" + yyextra->current->name;
1239 startScope(yyscanner,yyextra->last_entry.get());
1242<FEnum>"end"{BS}"enum" {
1243 yyextra->last_entry->parent()->endBodyLine = yyextra->lineNr;
1244 if (!
endScope(yyscanner,yyextra->current_root))
1248 yyextra->typeMode =
false;
1254<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}({PREFIX}{BS_})?/{SUBPROG}{BS_} {
1257 addInterface(yyscanner,
"$interface$", yyextra->ifType);
1258 startScope(yyscanner,yyextra->last_entry.get());
1263 yy_push_state(SubprogPrefix,yyscanner);
1266<SubprogPrefix>{BS}{SUBPROG}{BS_} {
1273 yyextra->current->bodyLine = yyextra->lineNr + yyextra->lineCountPrepass + 1;
1274 yyextra->current->startLine = yyextra->lineNr;
1277<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} {
1282 addInterface(yyscanner,
"$interface$", yyextra->ifType);
1283 startScope(yyscanner,yyextra->last_entry.get());
1288 yy_push_state(Subprog,yyscanner);
1289 yyextra->current->bodyLine = yyextra->lineNr + yyextra->lineCountPrepass + 1;
1290 yyextra->current->startLine = yyextra->lineNr;
1294<Subprog>{ID} { yyextra->current->name = yytext;
1298 if ((yyextra->current_root) &&
1299 (yyextra->current_root->section.isClass() ||
1300 yyextra->current_root->section.isNamespace()))
1302 yyextra->current->name= yyextra->current_root->name +
"::" + yyextra->current->name;
1304 yyextra->modifiers[yyextra->current_root][yyextra->current->name.lower().str()].returnName = std::move(returnName);
1309 yyextra->current_root->name,
"$interface$",
DString(yytext).lower());
1312 BEGIN(Parameterlist);
DString substitute(const DString &s, const DString &src, const DString &dst)
substitute all occurrences of src in s by dst
1314<Parameterlist>"(" { yyextra->current->args =
"("; }
1316 yyextra->current->args +=
")";
1319 startScope(yyscanner,yyextra->last_entry.get());
DString removeRedundantWhiteSpace(const DString &s)
1322<Parameterlist>{COMMA}|{BS} { yyextra->current->args += yytext;
1326 if (!yyextra->current->argList.empty())
1328 yyextra->current->argList.back().docs = c->
str;
1332<Parameterlist>{ID} {
1336 yyextra->current->args += param;
1340 yyextra->current->argList.
push_back(arg);
1342<Parameterlist>{NOARGS} {
1346 startScope(yyscanner,yyextra->last_entry.get());
1349<SubprogBody>result{BS}\({BS}{ID} {
1350 if (yyextra->functionLine)
1353 result= result.
mid(result.
find(
'(')+1);
1355 yyextra->modifiers[yyextra->current_root->parent()][yyextra->current_root->name.lower().str()].returnName = result;
1362<FVariable,SubprogBody,ModuleBody,TypedefBody,TypedefBodyContains>"!<" {
1365 yyextra->current->docLine = yyextra->lineNr;
1366 yyextra->docBlockJavaStyle =
false;
1367 yyextra->docBlock.clear();
1370 yy_push_state(DocBackLine,yyscanner);
1375 if (YY_START == String)
1377 yyextra->colNr -= (int)yyleng;
1382 if ((YY_START != StrIgnore) && (YY_START != String))
1384 yy_push_state(YY_START,yyscanner);
1386 yyextra->debugStr=
"*!";
#define Config_getBool(name)
1391 yyextra->docBlock+=yytext;
1393<DocBackLine>"\n"{BS}"!"("<"|"!"+) {
1394 yyextra->docBlock+=
"\n";
1399 yyextra->colNr -= 1;
1403 std::shared_ptr<Entry> tmp_entry = yyextra->current;
1405 if (yyextra->last_enum)
1407 yyextra->current = yyextra->last_enum;
1411 yyextra->current = yyextra->last_entry;
1415 yyextra->current = std::move(tmp_entry);
1421 else if (yyextra->vtype ==
V_RESULT)
1426 yyextra->docBlock.clear();
DString stripIndentation(const DString &s, bool skipFirstLine)
1429<Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains,FEnum>^{BS} {
static int computeIndent(const char *str, size_t length)
1432<Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains,FEnum>"!>" {
1433 yy_push_state(YY_START,yyscanner);
1434 yyextra->current->docLine = yyextra->lineNr;
1435 yyextra->docBlockJavaStyle =
false;
1436 if (YY_START==SubprogBody) yyextra->docBlockInBody =
true;
1437 yyextra->docBlock.clear();
1445<DocBlock>({CMD}{CMD}){ID}/[^a-z_A-Z0-9] {
1446 yyextra->docBlock += yytext;
1448<DocBlock>{CMD}("f$"|"f["|"f{"|"f(") {
1449 yyextra->docBlock += yytext;
1450 yyextra->docBlockName=&yytext[1];
1451 if (yyextra->docBlockName.at(1)==
'[')
1453 yyextra->docBlockName.at(1)=
']';
1455 if (yyextra->docBlockName.at(1)==
'{')
1457 yyextra->docBlockName.at(1)=
'}';
1459 if (yyextra->docBlockName.at(1)==
'(')
1461 yyextra->docBlockName.at(1)=
')';
1463 yyextra->fencedSize=0;
1465 BEGIN(DocCopyBlock);
1467<DocBlock>{CMD}"ifile"{B}+"\""[^\n\"]+"\"" {
1468 yyextra->fileName = &yytext[6];
1469 yyextra->fileName = yyextra->fileName.stripWhiteSpace();
1470 yyextra->fileName = yyextra->fileName.mid(1,yyextra->fileName.length()-2);
1471 yyextra->docBlock += yytext;
1473<DocBlock>{CMD}"ifile"{B}+{FILEMASK} {
1474 yyextra->fileName = &yytext[6];
1475 yyextra->fileName = yyextra->fileName.stripWhiteSpace();
1476 yyextra->docBlock += yytext;
1478<DocBlock>{CMD}"iline"{LINENR}/[\n\.] |
1479<DocBlock>{CMD}"iline"{LINENR}{B} {
1484 warn(yyextra->fileName,yyextra->lineNr,
"Invalid line number '{}' for iline command",yytext);
1488 yyextra->lineNr = nr;
1490 yyextra->docBlock += yytext;
int toInt(bool *ok=nullptr, int base=10) const
1492<DocBlock>{B}*"<"{PRE}">" {
1493 yyextra->docBlock += yytext;
1494 yyextra->docBlockName=
"<pre>";
1495 yyextra->fencedSize=0;
1497 BEGIN(DocCopyBlock);
1499<DocBlock>{B}*"<"<CODE>">" {
1500 yyextra->docBlock += yytext;
1501 yyextra->docBlockName=
"<code>";
1502 yyextra->fencedSize=0;
1504 BEGIN(DocCopyBlock);
1506<DocBlock>{CMD}"startuml"/[^a-z_A-Z0-9\-] {
1507 yyextra->docBlock += yytext;
1508 yyextra->docBlockName=
"uml";
1509 yyextra->fencedSize=0;
1511 BEGIN(DocCopyBlock);
1513<DocBlock>{CMD}("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"manonly"|"rtfonly"|"docbookonly"|"dot"|"msc"|"mermaid"|"code")/[^a-z_A-Z0-9\-] {
1514 yyextra->docBlock += yytext;
1515 yyextra->docBlockName=&yytext[1];
1516 yyextra->fencedSize=0;
1518 BEGIN(DocCopyBlock);
1520<DocBlock>"~~~"[~]* {
1522 yyextra->docBlock += pat;
1523 yyextra->docBlockName=
"~~~";
1524 yyextra->fencedSize=pat.
length();
1526 BEGIN(DocCopyBlock);
1528<DocBlock>"```"[`]*/(".")?[a-zA-Z0-9#_-]+ |
1529<DocBlock>"```"[`]*/"{"[^}]+"}" |
1530<DocBlock>"```"[`]* {
1532 yyextra->docBlock += pat;
1533 yyextra->docBlockName=
"```";
1534 yyextra->fencedSize=pat.
length();
1536 BEGIN(DocCopyBlock);
1538<DocBlock>"\\ilinebr "{BS} {
1540 int extraSpaces = std::max(0,
static_cast<int>(yyleng-9-yyextra->curIndent-2));
1541 indent.
fill(
' ',extraSpaces);
1543 yyextra->docBlock +=
"\\ilinebr ";
1544 yyextra->docBlock += indent;
DString fill(char c, size_t len)
Fills a string with a predefined character.
1547<DocBlock>[^@*`~\/\\\n]+ {
1548 yyextra->docBlock += yytext;
1550<DocBlock>"\n"{BS}"!"(">"|"!"+) {
1551 yyextra->docBlock+=
"\n";
1556 yyextra->colNr -= 1;
1562 yyextra->docBlock += *yytext;
1567<DocCopyBlock>"</"{PRE}">" {
1568 yyextra->docBlock += yytext;
1569 if (yyextra->docBlockName==
"<pre>")
1571 yyextra->docBlockName=
"";
1576<DocCopyBlock>"</"{CODE}">" {
1577 yyextra->docBlock += yytext;
1578 if (yyextra->docBlockName==
"<code>")
1580 yyextra->docBlockName=
"";
1585<DocCopyBlock>{CMD}("f$"|"f]"|"f}"|"f)") {
1586 yyextra->docBlock += yytext;
1587 if (yyextra->docBlockName==&yytext[1])
1589 yyextra->docBlockName=
"";
1594<DocCopyBlock>{CMD}("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endmanonly"|"endrtfonly"|"enddot"|"endmsc"|"endmermaid"|"enduml"|"endcode")/[^a-z_A-Z0-9] {
1595 yyextra->docBlock += yytext;
1596 if (&yytext[4]==yyextra->docBlockName)
1598 yyextra->docBlockName=
"";
1604<DocCopyBlock>^{B}*{COMM} {
1606<DocCopyBlock>"~~~"[~]* {
1608 yyextra->docBlock += pat;
1609 if (yyextra->docBlockName ==
"~~~" && yyextra->fencedSize==pat.
length())
1615<DocCopyBlock>"```"[`]* {
1617 yyextra->docBlock += pat;
1618 if (yyextra->docBlockName ==
"```" && yyextra->fencedSize==pat.
length())
1625<DocCopyBlock>[^<@/\*\]!`~"\$\\\n]+ {
1626 yyextra->docBlock += yytext;
1629 yyextra->docBlock += *yytext;
1633 yyextra->docBlock += *yytext;
1637<Prototype>{BS}{SUBPROG}{BS_} {
1638 BEGIN(PrototypeSubprog);
1640<Prototype,PrototypeSubprog>{BS}{SCOPENAME}?{BS}{ID} {
1643 BEGIN(PrototypeArgs);
1646"("|")"|","|{BS_} { yyextra->current->args += yytext; }
1647{ID} { yyextra->current->args += yytext;
1659 yyextra->debugStr=
"";
1666 if (yyextra->parsingPrototype)
1670 else if ( yyextra->includeStackPtr <= 0 )
1672 if (YY_START!=INITIAL && YY_START!=Start)
1674 DBG_CTX((stderr,
"==== Error: EOF reached in wrong state (end missing)"));
1699 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
1701 yyextra->lineNr+=yyextra->lineCountPrepass;
1702 yyextra->lineCountPrepass=0;
1703 yyextra->comments.clear();
1714 if (c==
'\t') col+=tabSize-(col%tabSize);
1715 else if (c==
'\n') col=0;
1723 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
1725 for (
const auto &cip : yyextra->comments)
1729 if (c>=from && c<=to)
1740 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
1744 yyextra->last_entry->brief = c->
str;
1749 if (parameter) parameter->
docs = c->
str;
1755 for(
int i=0; i<length; i++)
1775 int parseState = Start;
1776 char quoteSymbol = 0;
1778 int commentIndex = -1;
1780 if (ch !=
'\0') parseState = String;
1782 for(
int i=0; i<length && parseState!=Comment; i++)
1786 if (parseState==String)
1788 if (buf[i]==
'\\') i++;
1797 if (buf[i]==quoteSymbol)
1803 else if (parseState==Start)
1805 parseState = String;
1806 quoteSymbol = buf[i];
1812 if (parseState==Start)
1814 parseState = Comment;
1833 return commentIndex;
1841 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
1842 size_t length = yyextra->inputStringPrepass.length();
1843 for (
size_t i=index+1; i<length; i++) {
1844 if (yyextra->inputStringPrepass[i]==
'!' && i<length-1 && yyextra->inputStringPrepass[i+1]==
'<') {
1845 yyextra->comments.emplace_back(index, yyextra->inputStringPrepass.right(length-i-2));
1848 yyextra->inputStringPrepass.resize(index);
1855 for(
int i=length; i>pos; i--)
1856 contents[i]=contents[i-1];
1866 int prevLineLength=0;
1867 int prevLineAmpOrExclIndex=-1;
1869 char prevQuote =
'\0';
1870 char thisQuote =
'\0';
1871 bool emptyLabel=
true;
1872 bool commented=
false;
1873 bool inSingle=
false;
1874 bool inDouble=
false;
1875 bool inBackslash=
false;
1876 bool fullCommentLine=
true;
1877 bool artificialComment=
false;
1879 int newContentsSize = (int)strlen(contents)+3;
1880 char* newContents = (
char*)malloc(newContentsSize);
1885 sizCont = strlen(contents);
1886 for(
size_t i=0;i<sizCont;i++) {
1888 char c = contents[i];
1889 if (artificialComment && c !=
'\n')
1891 if (c ==
'!' && spaces)
1893 newContents[j++] = c;
1894 artificialComment =
false;
1899 else if (c ==
' ' || c ==
'\t')
continue;
1909 if (j>=newContentsSize-3) {
1910 newContents = (
char*)realloc(newContents, newContentsSize+1000);
1911 newContentsSize = newContentsSize+1000;
1916 if (!fullCommentLine)
1918 prevLineLength=column;
1919 prevLineAmpOrExclIndex=
getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength,prevQuote);
1920 if (prevLineAmpOrExclIndex == -1) prevLineAmpOrExclIndex = column - 1;
1923 prevLineAmpOrExclIndex = -1;
1929 prevLineLength+=column;
1933 hasContLine[curLine - 1] = 1;
1936 artificialComment=
false;
1938 fullCommentLine=
true;
1943 prevQuote = thisQuote;
1956 newContents[j]=
'\000';
1957 newContentsSize = (int)strlen(newContents);
1958 if (newContents[newContentsSize - 1] !=
'\n')
1961 newContents = (
char*)realloc(newContents, newContentsSize+2);
1962 newContents[newContentsSize] =
'\n';
1963 newContents[newContentsSize + 1] =
'\000';
1969 if ((column <= fixedCommentAfter) && (column!=6) && !commented)
1972 fullCommentLine=
false;
1976 inBackslash = !inBackslash;
1983 inSingle = !inSingle;
1984 if (inSingle) thisQuote = c;
1985 else thisQuote =
'\0';
1993 inDouble = !inDouble;
1994 if (inDouble) thisQuote = c;
1995 else thisQuote =
'\0';
2000 inBackslash =
false;
2007 if ((column <= fixedCommentAfter) && (column!=6))
2015 else if ((c ==
'!') && !inDouble && !inSingle)
2022 if (!commented) fullCommentLine=
false;
2029 if (!commented && (column < 6) && ((c -
'0') >= 0) && ((c -
'0') <= 9))
2033 else if (column==6 && emptyLabel)
2035 if (!commented) fullCommentLine=
false;
2040 if (prevLineAmpOrExclIndex==-1)
2049 if (curLine != 1)
insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex+skipped,
'&');
2055 hasContLine[curLine - 1] = 1;
2064 else if ((column > fixedCommentAfter) && !commented)
2075 artificialComment =
true;
2087 if (!commented) fullCommentLine=
false;
2103 newContents = (
char*)realloc(newContents, 2);
2104 newContents[0] =
'\n';
2105 newContents[1] =
'\000';
2107 else if (newContents[j] ==
'\n')
2109 newContents = (
char*)realloc(newContents, j+2);
2110 newContents[j + 1] =
'\000';
2114 newContents = (
char*)realloc(newContents, j+3);
2115 newContents[j + 1] =
'\n';
2116 newContents[j + 2] =
'\000';
2125 static const std::unordered_set<std::string> fortran_C_keywords = {
2126 "character",
"call",
"close",
"common",
"continue",
2127 "case",
"contains",
"cycle",
"class",
"codimension",
2128 "concurrent",
"contiguous",
"critical"
2131 if (*contents !=
'c' && *contents !=
'C')
return false;
2133 const char *c = contents;
2135 while (*c && *c !=
' ') {keyword += *c; c++;}
2136 keyword = keyword.
lower();
2138 return (fortran_C_keywords.find(keyword.
str()) != fortran_C_keywords.end());
2145 bool skipLine=
false;
2151 size_t sizCont = contents.
length();
2152 for (
size_t i=0;i<sizCont;i++)
2156 switch(contents.
at(i))
2163 column += tabSize-1;
2180 if (column==1)
return true;
2181 if (skipLine)
break;
2184 if (column!=6) skipLine=
true;
2187 if (skipLine)
break;
2188 if (column>=7)
return true;
2211 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2212 if (yyextra->includeStackCnt <= yyextra->includeStackPtr)
2214 yyextra->includeStackCnt++;
2215 yyextra->includeStack = (YY_BUFFER_STATE *)realloc(yyextra->includeStack, yyextra->includeStackCnt *
sizeof(YY_BUFFER_STATE));
2217 yyextra->includeStack[yyextra->includeStackPtr++] = YY_CURRENT_BUFFER;
2218 yy_switch_to_buffer(yy_scan_string(buffer.
data(),yyscanner),yyscanner);
2225 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2227 yyextra->includeStackPtr --;
2228 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
2229 yy_switch_to_buffer( yyextra->includeStack[yyextra->includeStackPtr], yyscanner );
2233static void copyEntry(std::shared_ptr<Entry> dest,
const std::shared_ptr<Entry> &src)
2235 dest->type = src->type;
2236 dest->fileName = src->fileName;
2237 dest->startLine = src->startLine;
2238 dest->bodyLine = src->bodyLine;
2239 dest->endBodyLine = src->endBodyLine;
2240 dest->args = src->args;
2241 dest->argList = src->argList;
2242 dest->doc = src->doc;
2243 dest->docLine = src->docLine;
2244 dest->docFile = src->docFile;
2245 dest->brief = src->brief;
2246 dest->briefLine= src->briefLine;
2247 dest->briefFile= src->briefFile;
2257 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2258 if (yyextra->moduleProcedures.empty())
return;
2261 std::map<std::string,std::shared_ptr<Entry>> procMap;
2263 for (
const auto& cf: current_root->
children())
2265 if (!cf->section.isFunction())
2274 procMap.emplace(name.
str(), cf);
2280 for (
const auto& ce1: yyextra->moduleProcedures)
2282 if (procMap.find(ce1->name.str())!=procMap.end())
2284 std::shared_ptr<Entry> proc = procMap[ce1->name.str()];
2288 yyextra->moduleProcedures.clear();
2297 extracted.
remove(0, start+1);
2301 size_t length = extracted.
length();
2313 if (parensPart.
length() == 1)
2328 return "bind(C, name=" + parensPart +
")";
2369 else if (mdfString.
contains(
"intent"))
2378 else if (mdfString==
"public")
2382 else if (mdfString==
"private")
2386 else if (mdfString==
"protected")
2390 else if (mdfString==
"optional")
2394 else if (mdfString==
"allocatable")
2398 else if (mdfString==
"external")
2402 else if (mdfString==
"intrinsic")
2406 else if (mdfString==
"parameter")
2410 else if (mdfString==
"pointer")
2414 else if (mdfString==
"target")
2418 else if (mdfString==
"save")
2422 else if (mdfString==
"nopass")
2426 else if (mdfString==
"deferred")
2430 else if (mdfString==
"non_overridable")
2434 else if (mdfString==
"contiguous")
2438 else if (mdfString==
"volatile")
2440 newMdf.
volat =
true;
2442 else if (mdfString==
"value")
2444 newMdf.
value =
true;
2446 else if (mdfString.
contains(
"pass"))
2480 if ((!byTypeName && arg.
name.
lower() == cname) ||
2481 (byTypeName && arg.
type.
lower() == cname)
2496 if (!typeName.
empty()) typeName +=
", ";
2501 if (!typeName.
empty()) typeName +=
", ";
2506 if (!typeName.
empty()) typeName +=
", ";
2507 typeName +=
"optional";
2511 if (!typeName.
empty()) typeName +=
", ";
2512 typeName +=
"allocatable";
2516 if (!typeName.
contains(
"external"))
2518 if (!typeName.
empty()) typeName +=
", ";
2519 typeName +=
"external";
2524 if (!typeName.
empty()) typeName +=
", ";
2525 typeName +=
"intrinsic";
2529 if (!typeName.
empty()) typeName +=
", ";
2530 typeName +=
"parameter";
2534 if (!typeName.
empty()) typeName +=
", ";
2535 typeName +=
"pointer";
2539 if (!typeName.
empty()) typeName +=
", ";
2540 typeName +=
"target";
2544 if (!typeName.
empty()) typeName +=
", ";
2549 if (!typeName.
empty()) typeName +=
", ";
2550 typeName +=
"deferred";
2554 if (!typeName.
empty()) typeName +=
", ";
2555 typeName +=
"non_overridable";
2559 if (!typeName.
empty()) typeName +=
", ";
2560 typeName +=
"nopass";
2564 if (!typeName.
empty()) typeName +=
", ";
2567 typeName +=
"(" + mdfs.
passVar +
")";
2571 if (!typeName.
empty()) typeName +=
", ";
2576 if (!typeName.
empty()) typeName +=
", ";
2577 typeName +=
"public";
2581 if (!typeName.
empty()) typeName +=
", ";
2582 typeName +=
"private";
2586 if (!typeName.
empty()) typeName +=
", ";
2587 typeName +=
"protected";
2591 if (!typeName.
empty()) typeName +=
", ";
2592 typeName +=
"contiguous";
2596 if (!typeName.
empty()) typeName +=
", ";
2597 typeName +=
"volatile";
2601 if (!typeName.
empty()) typeName +=
", ";
2602 typeName +=
"value";
2625 ent->
spec.setFinal(
true);
2629 ent->
virt = Specifier::Pure;
2638 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2640 yyextra->current_root= scope;
2642 yyextra->modifiers.emplace(scope, std::map<std::string,SymbolModifiers>());
2645 yyextra->current = std::make_shared<Entry>();
2654 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2655 if (yyextra->global_scope == scope)
2657 yyextra->global_scope =
nullptr;
2665 if (yyextra->current_root->parent() || isGlobalRoot)
2667 yyextra->current_root= yyextra->current_root->parent();
2671 fprintf(stderr,
"parse error in end <scopename>\n");
2677 yyextra->current = std::make_shared<Entry>();
2681 std::map<std::string,SymbolModifiers>& mdfsMap = yyextra->modifiers[scope];
2683 if (scope->
section.isFunction())
2686 for (
const auto &kv : mdfsMap)
2700 if (yyextra->modifiers[scope].find(returnName.
str())!=yyextra->modifiers[scope].end())
2702 scope->
type = yyextra->modifiers[scope][returnName.
str()].type;
2707 if (scope->
section.isClass() && scope->
spec.isInterface())
2714 for (
const auto &ce : scope->
children())
2716 if (!ce->section.isFunction())
2726 arg->
type =
"external " + ce->type +
"(";
2727 for (
size_t i=0; i<ce->argList.size(); i++)
2733 const Argument &subarg = ce->argList.at(i);
2741 yyextra->modifiers.erase(scope);
2747 if (!scope->
section.isFunction())
2750 for (
const auto &ce : scope->
children())
2752 if (!ce->section.isVariable() && !ce->section.isFunction() && !ce->section.isClass())
2756 if (mdfsMap.find(ce->name.lower().str())!=mdfsMap.end())
2760 if (ce->section.isVariable() || ce->section.isFunction())
2768 yyextra->modifiers.erase(scope);
2782 bool procMapCreated =
false;
2783 std::unordered_map<std::string,std::shared_ptr<Entry>> procMap;
2786 bool interfMapCreated =
false;
2787 std::unordered_map<std::string,std::shared_ptr<Entry>> interfMap;
2790 for (
const auto &ce: scope->
children())
2792 if (!ce->section.isClass())
2796 std::unordered_map<std::string,std::shared_ptr<Entry>> methodMap;
2797 for (
auto &ct: ce->children())
2799 if (!ct->section.isFunction())
2802 if (ct->type==
"generic")
2805 if (ct->virt==Specifier::Pure)
2809 if (!procMapCreated)
2811 for (
const auto &cf: scope->
children())
2813 if (cf->section.isFunction())
2815 procMap.emplace(cf->name.str(), cf);
2818 procMapCreated =
true;
2823 if (procMap.find(implName.
str())!=procMap.end())
2825 std::shared_ptr<Entry> proc = procMap[implName.
str()];
2826 ct->args = proc->args;
2828 if (ct->brief.empty())
2830 ct->brief = proc->brief;
2831 ct->briefLine = proc->briefLine;
2832 ct->briefFile = proc->briefFile;
2834 if (ct->doc.empty())
2836 ct->doc = proc->doc;
2837 ct->docLine = proc->docLine;
2838 ct->docFile = proc->docFile;
2840 methodMap.emplace(ct->name.str(), ct);
2845 for (
auto &ct: ce->children())
2847 if (!ct->section.isFunction())
2850 if (ct->virt != Specifier::Pure)
2854 if (!interfMapCreated)
2856 for(
const auto &cf: scope->
children())
2858 if (cf->section.isClass() && cf->spec.isInterface() && cf->type==
"abstract")
2860 std::shared_ptr<Entry> ci = cf->children().front();
2861 interfMap.emplace(ci->name.str(), ci);
2864 interfMapCreated =
true;
2869 if (interfMap.find(implName.
str())!= interfMap.end() )
2871 std::shared_ptr<Entry> proc = interfMap[implName.
str()];
2872 ct->args = proc->args;
2874 if (ct->brief.empty())
2876 ct->brief = proc->brief;
2877 ct->briefLine = proc->briefLine;
2878 ct->briefFile = proc->briefFile;
2880 if (ct->doc.empty())
2882 ct->doc = proc->doc;
2883 ct->docLine = proc->docLine;
2884 ct->docFile = proc->docFile;
2887 methodMap.emplace(ct->name.str(), ct);
2893 for (
auto &ct: ce->children())
2895 if (!ct->section.isFunction())
2898 if (ct->type!=
"generic")
2902 DString methodName = ct->args;
2903 if (methodMap.find(methodName.
str()) != methodMap.end())
2905 std::shared_ptr<Entry> method = methodMap[methodName.
str()];
2906 ct->args = method->args;
2908 if (ct->brief.empty())
2910 ct->brief = method->brief;
2911 ct->briefLine = method->briefLine;
2912 ct->briefFile = method->briefFile;
2914 if (ct->doc.empty())
2916 ct->doc = method->doc;
2917 ct->docLine = method->docLine;
2918 ct->docFile = method->docFile;
2928 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2930 while ( c < max_size && yyextra->inputString[yyextra->inputPosition] )
2932 *buf = yyextra->inputString[yyextra->inputPosition++] ;
2940 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2941 yyextra->last_entry.reset();
2946 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2947 if (yyextra->typeMode)
2949 yyextra->current->protection = yyextra->typeProtection;
2951 else if (yyextra->current_root && yyextra->current_root->section.isClass() && yyextra->current_root->spec.isInterface())
2953 yyextra->current->protection = Protection::Public;
2955 else if (yyextra->current_root && yyextra->current_root->section.isFunction())
2957 yyextra->current->protection = Protection::Private;
2961 yyextra->current->protection = yyextra->defaultProtection;
2963 yyextra->current->mtype = MethodTypes::Method;
2964 yyextra->current->virt = Specifier::Normal;
2965 yyextra->current->isStatic =
false;
2966 yyextra->current->lang = SrcLangExt::Fortran;
2967 yyextra->commentScanner.initGroupInfo(yyextra->current.get());
2975 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2976 if (case_insens) yyextra->current->name = yyextra->current->name.lower();
2978 yyextra->last_entry = yyextra->current;
2979 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
2985 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
2986 DBG_CTX((stderr,
"0=========> got module %s\n",
qPrint(name)));
2989 yyextra->current->section = EntryType::makeNamespace();
2991 yyextra->current->section = EntryType::makeFunction();
2995 yyextra->current->name = name;
2999 DString fname = yyextra->fileName;
3000 size_t index1 = fname.
rfind(
'/');
3001 size_t index2 = fname.
rfind(
'\\');
3005 if (yyextra->mainPrograms) fname +=
"__" +
DString().
setNum(yyextra->mainPrograms);
3006 yyextra->mainPrograms++;
3008 yyextra->current->name =
substitute(fname,
".",
"_");
3010 yyextra->current->type =
"program";
3011 yyextra->current->fileName = yyextra->fileName;
3012 yyextra->current->bodyLine = yyextra->lineNr;
3013 yyextra->current->startLine = yyextra->lineNr;
3014 yyextra->current->protection = Protection::Public ;
3016 startScope(yyscanner,yyextra->last_entry.get());
3022 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3023 DBG_CTX((stderr,
"1=========> got subprog, type: %s\n",
qPrint(text)));
3024 yyextra->subrCurrent.push_back(yyextra->current);
3025 yyextra->current->section = EntryType::makeFunction();
3028 yyextra->current->type +=
" " + subtype;
3032 yyextra->current->virt = Specifier::Virtual;
3034 yyextra->current->fileName = yyextra->fileName;
3035 yyextra->current->bodyLine = yyextra->lineNr;
3036 yyextra->current->startLine = yyextra->lineNr;
3037 yyextra->current->args.
clear();
3038 yyextra->current->argList.clear();
3040 yyextra->docBlock.clear();
3049 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3050 if (YY_START == Start)
3054 yy_push_state(ModuleBody,yyscanner);
3057 yyextra->current->section = EntryType::makeClass();
3058 yyextra->current->spec =
TypeSpecifier().setInterface(
true);
3059 yyextra->current->name = name;
3064 yyextra->current->type =
"abstract";
3068 yyextra->current->type =
"generic";
3074 yyextra->current->type =
"";
3078 if ((yyextra->current_root) &&
3079 (yyextra->current_root->section.isClass() ||
3080 yyextra->current_root->section.isNamespace()))
3082 yyextra->current->name= yyextra->current_root->name +
"::" + yyextra->current->name;
3085 yyextra->current->fileName = yyextra->fileName;
3086 yyextra->current->bodyLine = yyextra->lineNr;
3087 yyextra->current->startLine = yyextra->lineNr;
3098 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3101 for (
Argument &a:yyextra->current_root->argList)
3116 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3119 yyextra->current->briefFile = yyextra->fileName;
3120 yyextra->current->briefLine = yyextra->lineNr;
3124 yyextra->current->docFile = yyextra->fileName;
3125 yyextra->current->docLine = yyextra->lineNr;
3133 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3138 if (yyextra->docBlockInBody && hideInBodyDocs)
3140 yyextra->docBlockInBody =
false;
3143 DBG_CTX((stderr,
"call parseCommentBlock [%s]\n",
qPrint(doc)));
3144 int lineNr = brief ? yyextra->current->briefLine : yyextra->current->docLine;
3146 bool needsEntry =
false;
3147 Markdown markdown(yyextra->fileName,lineNr);
3151 while (yyextra->commentScanner.parseCommentBlock(
3152 yyextra->thisParser,
3153 yyextra->docBlockInBody ? yyextra->subrCurrent.back().get() : yyextra->current.get(),
3157 yyextra->docBlockInBody ?
false : brief,
3158 yyextra->docBlockInBody ?
false : yyextra->docBlockJavaStyle,
3159 yyextra->docBlockInBody,
3160 yyextra->defaultProtection,
3167 DBG_CTX((stderr,
"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.
data()+position,needsEntry));
3170 DBG_CTX((stderr,
"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.
data()+position,needsEntry));
3173 yyextra->docBlockInBody =
false;
3180 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3184 std::shared_ptr<Entry> tmp_entry = yyextra->current;
3185 yyextra->current = yyextra->subrCurrent.
back();
3188 yyextra->current->inbodyDocs =
"";
3196 int dir1 = yyextra->modifiers[yyextra->current_root][yyextra->argName.lower().str()].direction;
3208 if (!loc_doc.
empty() && (loc_doc.
lower() != yyextra->argName.
lower()))
3211 yyextra->argName +
" " + loc_doc,brief);
3217 warn(yyextra->fileName,yyextra->lineNr,
"Routine: {}{} inconsistency between intent attribute and documentation for parameter {}:",
3218 yyextra->current->name,yyextra->current->args,yyextra->argName);
3220 yyextra->argName +
" " + loc_doc,brief);
3233 yyextra->current = tmp_entry;
3237 yyextra->argName +
" " + loc_doc,brief);
3241 warn(yyextra->fileName,yyextra->lineNr,
"Routine: {}{} inconsistency between intent attribute and documentation for parameter {}:",
3242 yyextra->current->name,yyextra->current->args,yyextra->argName);
3244 yyextra->argName +
" " + loc_doc,brief);
3255 if (!loc_doc.
empty() && (loc_doc.
lower() != yyextra->argName.
lower()))
3258 yyextra->argName +
" " + loc_doc,brief);
3263 warn(yyextra->fileName,yyextra->lineNr,
"Routine: {}{} inconsistency between intent attribute and documentation for parameter {}:",
3264 yyextra->current->name,yyextra->current->args,yyextra->argName);
3266 yyextra->argName +
" " + loc_doc,brief);
3270 else if (!loc_doc.
empty() && (loc_doc.
lower() != yyextra->argName.
lower()))
3273 yyextra->argName +
" " + loc_doc,brief);
3277 yyextra->current = tmp_entry;
3283 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3287 std::shared_ptr<Entry> tmp_entry = yyextra->current;
3288 yyextra->current = yyextra->subrCurrent.
back();
3291 yyextra->current->inbodyDocs =
"";
3300 if (!loc_doc.
empty() && (loc_doc.
lower() != yyextra->argName.
lower()))
3306 yyextra->current = std::move(tmp_entry);
3314 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3315 char *tmpBuf =
nullptr;
3318 if (fileBuf==
nullptr || fileBuf[0]==
'\0')
return;
3320 yyextra->defaultProtection = Protection::Public;
3321 yyextra->inputString = fileBuf;
3322 yyextra->inputPosition = 0;
3323 yyextra->inputStringPrepass =
nullptr;
3324 yyextra->inputPositionPrepass = 0;
3327 yyextra->current_root = rt.get();
3328 yyextra->global_root = rt;
3332 if (yyextra->isFixedForm)
3334 yyextra->fixedCommentAfter =
Config_getInt(FORTRAN_COMMENT_AFTER);
3335 msg(
"Prepassing fixed form of {}\n", fileName);
3341 yyextra->inputString =
prepassFixedForm(fileBuf,
nullptr,yyextra->fixedCommentAfter);
3350 else if (yyextra->inputString[strlen(fileBuf)-1] !=
'\n')
3352 tmpBuf = (
char *)malloc(strlen(fileBuf)+2);
3353 strcpy(tmpBuf,fileBuf);
3354 tmpBuf[strlen(fileBuf)]=
'\n';
3355 tmpBuf[strlen(fileBuf)+1]=
'\000';
3356 yyextra->inputString = tmpBuf;
3359 yyextra->lineNr= 1 ;
3360 yyextra->fileName = fileName;
3361 msg(
"Parsing file {}...\n",yyextra->fileName);
3363 yyextra->global_scope = rt.get();
3366 yyextra->commentScanner.enterFile(yyextra->fileName,yyextra->lineNr);
3369 yyextra->current = std::make_shared<Entry>();
3370 yyextra->current->lang = SrcLangExt::Fortran;
3371 yyextra->current->name = yyextra->fileName;
3372 yyextra->current->section = EntryType::makeSource();
3373 yyextra->file_root = yyextra->current;
3374 yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current);
3375 yyextra->current->lang = SrcLangExt::Fortran;
3377 fortranscannerYYrestart(
nullptr, yyscanner );
3382 fortranscannerYYlex(yyscanner);
3383 yyextra->commentScanner.leaveFile(yyextra->fileName,yyextra->lineNr);
3385 if (yyextra->global_scope && yyextra->global_scope !=
INVALID_ENTRY)
3387 endScope(yyscanner,yyextra->current_root,
true);
3392 rt->program.str(std::string());
3394 yyextra->moduleProcedures.clear();
3397 free((
char*)tmpBuf);
3398 yyextra->inputString=
nullptr;
3400 if (yyextra->isFixedForm)
3402 free((
char*)yyextra->inputString);
3403 yyextra->inputString=
nullptr;
3436 const char *fileBuf,
3437 const std::shared_ptr<Entry> &root,
3440 struct yyguts_t *yyg = (
struct yyguts_t*)
p->yyscanner;
3441 yyextra->thisParser =
this;
3450 return extension!=extension.
lower();
3455 struct yyguts_t *yyg = (
struct yyguts_t*)
p->yyscanner;
3457 yyextra->parsingPrototype =
true;
3459 fortranscannerYYlex(
p->yyscanner);
3460 yyextra->parsingPrototype =
false;
3468 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3469 fprintf(stderr,
"********************************************************************\n");
3470 if (yyextra->blockLineNr == -1)
3472 fprintf(stderr,
"Error in file %s line: %d, state: %d(%s)\n",
3477 fprintf(stderr,
"Error in file %s line: %d, state: %d(%s), starting command: '%s' probable line reference: %d\n",
3478 qPrint(yyextra->fileName),yyextra->lineNr,YY_START,
stateToString(YY_START),
qPrint(yyextra->blockString),yyextra->blockLineNr);
3480 fprintf(stderr,
"********************************************************************\n");
3483 while (!yyextra->blockStack.empty()) yyextra->blockStack.pop();
3487 for (
const auto &ce : yyextra->global_root->children())
3489 if (ce == yyextra->file_root) start=
true;
3490 if (start) ce->reset();
3494 (void)yy_top_state(yyscanner);
3502 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3503 if ( yyg->yy_start_stack_ptr <= 0 )
3504 warn(yyextra->fileName,yyextra->lineNr,
"Unexpected statement '{}'",yytext );
3506 yy_pop_state(yyscanner);
3511 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3512 yyextra->blockString = text;
3513 yyextra->blockLineNr = yyextra->lineNr;
3514 yyextra->blockStack.emplace(yyextra->blockString,yyextra->blockLineNr);
3519 struct yyguts_t *yyg = (
struct yyguts_t*)yyscanner;
3520 if (yyextra->blockStack.empty())
3522 warn(yyextra->fileName,yyextra->lineNr,
"Internal inconsistency: empty stack while attempting popBlockState");
3526 yyextra->blockStack.pop();
3528 if (yyextra->blockStack.empty())
3530 yyextra->blockString.clear();
3531 yyextra->blockLineNr=-1;
3535 yyextra->blockString=yyextra->blockStack.top().blockString;
3536 yyextra->blockLineNr=yyextra->blockStack.top().blockLineNr;
3541#include "fortranscanner.l.h"
This class represents an function or template argument list.
Clang parser object for a single translation unit, which consists of a source file and the directly o...
DString & setNum(short n)
size_t rfind(char c, size_t pos=npos) const
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
char & at(size_t i)
Returns a reference to the character at index i.
DString & prepend(const char *s)
int contains(char c, bool cs=true) const
char & back()
Returns a reference to the last character.
bool stripPrefix(const DString &prefix)
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
bool startsWith(const char *s) const
static bool isFlagSet(const DebugMask mask)
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
static ParserManager * parserManager
const std::vector< std::shared_ptr< Entry > > & children() const
ArgumentList argList
member arguments as a list
EntryType section
entry type (see Sections);
Specifier virt
virtualness of the entry
Protection protection
class protection
TypeSpecifier spec
class/member specifiers
void removeSubEntry(const Entry *e)
bool needsPreprocessing(const DString &extension) const override
Returns true if the language identified by extension needs the C preprocessor to be run before feed t...
void parseInput(const DString &fileName, const char *fileBuf, const std::shared_ptr< Entry > &root, ClangTUParser *clangParser) override
Parses a single input file with the goal to build an Entry tree.
std::unique_ptr< Private > p
~FortranOutlineParser() override
FortranOutlineParser(FortranFormat format=FortranFormat::Unknown)
void parsePrototype(const DString &text) override
Callback function called by the comment block scanner.
Helper class to process markdown formatted text.
DString process(const DString &input, int &startNewlines, bool fromParseInput=false)
DString getParserName(const DString &extension)
Gets the name of the parser associated with given extension.
Wrapper class for a number of boolean properties.
#define Config_getInt(name)
DirIterator end(const DirIterator &) noexcept
const char * prepassFixedForm(const char *contents, int *hasContLine, int fixedCommentAfter)
bool recognizeFixedForm(const DString &contents, FortranFormat format)
FortranFormat convertFileNameFortranParserCode(const DString &fn)
static DString applyModifiers(DString typeName, const SymbolModifiers &mdfs)
const char * prepassFixedForm(const char *contents, int *hasContLine, int fixedCommentAfter)
static void initParser(yyscan_t yyscanner)
bool recognizeFixedForm(const DString &contents, FortranFormat format)
static void insertCharacter(char *contents, int length, int pos, char c)
static Argument * findArgument(Entry *subprog, DString name, bool byTypeName=false)
static bool keyWordsFortranC(const char *contents)
static void parseMain(yyscan_t yyscanner, const DString &fileName, const char *fileBuf, const std::shared_ptr< Entry > &rt, FortranFormat format)
fortranscannerYY_state extra
Private(FortranFormat fmt)
DString getFileNameExtension(const DString &fn)