/* -*- mode: fundamental; indent-tabs-mode: 1; -*- */
/*****************************************************************************
* Parser for Fortran90 F subset
*
* Copyright (C) by Anke Visser
* based on the work of Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation under the terms of the GNU General Public License is hereby
* granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
* Documents produced by Doxygen are derivative works derived from the
* input used in their production; they are not affected by this license.
*
*/
/* Developer notes.
*
* - Consider using startScope(), endScope() functions with module, program,
* subroutine or any other scope in fortran program.
*
* - Symbol modifiers (attributes) are collected using SymbolModifiers |= operator during
* substructure parsing. When substructure ends all modifiers are applied to actual
* entries in applyModifiers() functions.
*
* - How case insensitiveness should be handled in code?
* On one side we have arg->name and entry->name, on another side modifierMap[name].
* In entries and arguments case is the same as in code, in modifier map case is lowered and
* then it is compared to lowered entry/argument names.
*
* - Do not like constructs like aa{BS} or {BS}bb. Should try to handle blank space
* with separate rule?: It seems it is often necessary, because we may parse something like
* "functionA" or "MyInterface". So constructs like `(^|[ \t])interface({BS_}{ID})?/[ \t\n]'
* are desired.
*/
%{
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include "qtbc.h"
#include <qarray.h>
#include <qstack.h>
#include <qregexp.h>
#include <unistd.h>
#include <qfile.h>
#include <qmap.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 "fortrancode.h"
#include "pre.h"
#define YY_NEVER_INTERACTIVE 1
enum ScanVar { V_IGNORE, V_VARIABLE, V_PARAMETER};
// {{{ ----- Helper structs -----
//! Holds modifiers (ie attributes) for one symbol (variable, function, etc)
struct SymbolModifiers {
enum Protection {NONE_P, PUBLIC, PRIVATE};
enum Direction {NONE_D, IN, OUT, INOUT};
//!< This is only used with function return value.
QCString type, returnName;
Protection protection;
Direction direction;
bool optional;
QCString dimension;
bool allocatable;
bool external;
bool intrinsic;
bool parameter;
bool pointer;
bool target;
bool save;
SymbolModifiers() : type(), returnName(), protection(NONE_P), direction(NONE_D),
optional(FALSE), dimension(), allocatable(FALSE),
external(FALSE), intrinsic(FALSE), parameter(FALSE),
pointer(FALSE), target(FALSE), save(FALSE) {}
SymbolModifiers& operator|=(const SymbolModifiers &mdfs);
SymbolModifiers& operator|=(QCString mdfrString);
};
//ostream& operator<<(ostream& out, const SymbolModifiers& mdfs);
static const char *directionStrs[] =
{
"", "intent(in)", "intent(out)", "intent(inout)"
};
// }}}
/* -----------------------------------------------------------------
*
* statics
*/
static ParserInterface *g_thisParser;
static const char * inputString;
static int inputPosition;
static bool isFixedForm;
static QCString inputStringPrepass; ///< Input string for prepass of line cont. '&'
static unsigned int inputPositionPrepass;
static int lineCountPrepass = 0;
struct CommentInPrepass {
int column;
QCString str;
CommentInPrepass(int column, QCString str) : column(column), str(str) {}
};
static QList<CommentInPrepass> comments;
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
static QFile inputFile;
static QCString yyFileName;
static int yyLineNr = 1 ;
static Entry* current_root = 0 ;
static Entry* global_root = 0 ;
static Entry* file_root = 0 ;
static Entry* current = 0 ;
static Entry* last_entry = 0 ;
static ScanVar v_type = V_IGNORE; // type of parsed variable
static QList<Entry> moduleProcedures; // list of all interfaces which contain unresolved
// module procedures
static QCString docBlock;
static QCString docBlockName;
static bool docBlockInBody;
static bool docBlockJavaStyle;
static MethodTypes mtype;
static bool gstat;
static Specifier virt;
static QCString debugStr;
static QCString result; // function result
static Argument *parameter; // element of parameter list
static QCString argType; // fortran type of an argument of a parameter list
static QCString argName; // last identifier name in variable list
static QCString initializer; // initial value of a variable
static int initializerScope; // number if nested array scopes in initializer
static QCString useModuleName; // name of module in the use statement
static Protection defaultProtection;
static char stringStartSymbol; // single or double quote
//! Accumulated modifiers of current statement, eg variable declaration.
static SymbolModifiers currentModifiers;
//! Holds program scope->symbol name->symbol modifiers.
static QMap<Entry*,QMap<QCString,SymbolModifiers> > modifiers;
//-----------------------------------------------------------------------------
static int yyread(char *buf,int max_size);
static void startCommentBlock(bool);
static void handleCommentBlock(const QCString &doc,bool brief);
static void addCurrentEntry();
static void addModule(const char *name, bool isModule=FALSE);
static void addSubprogram(const char *text);
static void addInterface(QCString name);
static Argument *addFortranParameter(const QCString &type,const QCString &name, const QCString docs);
static void scanner_abort();
static void startScope(Entry *scope);
static bool endScope(Entry *scope, bool isGlobalRoot=FALSE);
static QCString getFullName(Entry *e);
static bool isTypeName(QCString name);
static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root);
static int getAmpersandAtTheStart(const char *buf, int length);
static int getAmpOrExclAtTheEnd(const char *buf, int length);
static void truncatePrepass(int index);
static void pushBuffer(QCString &buffer);
static void popBuffer();
static void extractPrefix(QCString& text);
//-----------------------------------------------------------------------------
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
//-----------------------------------------------------------------------------
%}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
IDSYM [a-z_A-Z0-9]
NOTIDSYM [^a-z_A-Z0-9]
SEPARATE [:, \t]
ID [a-z_A-Z%]+{IDSYM}*
PP_ID {ID}
LABELID [a-z_A-Z]+[a-z_A-Z0-9\-]*
SUBPROG (subroutine|function|block)
B [ \t]
BS [ \t]*
BS_ [ \t]+
COMMA {BS},{BS}
ARGS {BS}("("[^)]*")")
NOARGS {BS}"\n"
NUM_TYPE (complex|integer|logical|real)
KIND {ARGS}
CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS_}PRECISION|{CHAR}|TYPE{ARGS})
INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PRIVATE|PUBLIC|SAVE|TARGET)
ACCESS_SPEC (PRIVATE|PUBLIC)
/* Assume that attribute statements are almost the same as attributes. */
ATTR_STMT {ATTR_SPEC}|DIMENSION|{ACCESS_SPEC}
CONTAINS CONTAINS
PREFIX (RECURSIVE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,2}(RECURSIVE|PURE|ELEMENTAL)?
%option noyywrap
%option stack
%option caseless
/*%option debug */
//---------------------------------------------------------------------------------
/** fortran parsing states */
%x Subprog
%x SubprogPrefix
%x Parameterlist
%x SubprogBody
%x SubprogBodyContains
%x Start
%x Comment
%x Module
%x Program
%x ModuleBody
%x ModuleBodyContains
%x AttributeList
%x Variable
%x Initialization
%x ArrayInitializer
%x Typedef
%x TypedefBody
%x InterfaceBody
%x StrIgnore
%x String
%x Use
%x UseOnly
%x ModuleProcedure
%x Prepass
/** comment parsing states */
%x DocBlock
%x DocBackLine
%x EndDoc
%%
/*-----------------------------------------------------------------------------------*/
<*>^.*\n { // prepass: look for line continuations
//fprintf(stderr, "---%s", yytext);
int indexStart = getAmpersandAtTheStart(yytext, yyleng);
int indexEnd = getAmpOrExclAtTheEnd(yytext, yyleng);
if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp
indexEnd=-1;
if(indexEnd<0){ // ----- no ampersand as line continuation
if(YY_START == Prepass) { // last line in "continuation"
// Only take input after initial ampersand
inputStringPrepass+=(const char*)(yytext+(indexStart+1));
pushBuffer(inputStringPrepass);
yy_pop_state();
} else { // simple line
REJECT;
}
} else { // ----- line with continuation
if(YY_START != Prepass) {
comments.setAutoDelete(TRUE);
comments.clear();
yy_push_state(Prepass);
}
int length = inputStringPrepass.length();
// Only take input after initial ampersand
inputStringPrepass+=(const char*)(yytext+(indexStart+1));
lineCountPrepass ++;
// cut off & and remove following comment if present
truncatePrepass(length+indexEnd-(indexStart+1));
}
}
/*------ ignore strings */
<*>"\\\\" { /* ignore \\ */}
<*>"\\\""|\\\' { /* ignore \" and \' */}
<String>\"|\' { // string ends with next quote without previous backspace
if (yytext[0]!=stringStartSymbol) REJECT; // single vs double quote
// fprintf(stderr,"string end: %s\n",debugStr.data());
yy_pop_state();
}
<String>. { debugStr+=yytext; } // ignore String contents (especially '!')
<*>\"|\' { /* string starts */
if (YY_START == StrIgnore) REJECT; // ignore in simple comments
// fprintf(stderr,"string start: %c %d\n",yytext[0],yyLineNr);
yy_push_state(YY_START);
stringStartSymbol=yytext[0]; // single or double quote
BEGIN(String); debugStr="!^!";
}
/*------ ignore simple comment (not documentation comments) */
<*>"!"/[^<>\n] { if (YY_START == String) REJECT; // "!" is ignored in strings
// skip comment line (without docu comments "!>" "!<" )
/* ignore further "!" and ignore comments in Strings */
if ((YY_START != StrIgnore) && (YY_START != String))
{
yy_push_state(YY_START);
BEGIN(StrIgnore);
debugStr="*!";
//fprintf(stderr,"start comment %d\n",yyLineNr);
}
}
<StrIgnore>.?/\n { yy_pop_state(); // comment ends with endline character
//fprintf(stderr,"end comment %d %s\n",yyLineNr,debugStr.data());
} // comment line ends
<StrIgnore>. { debugStr+=yytext; }
/*------ use handling ------------------------------------------------------------*/
<Start,ModuleBody,TypedefBody,SubprogBody>"use"{BS_} {
if(YY_START == Start)
{
addModule(NULL);
yy_push_state(ModuleBody); //anon program
}
yy_push_state(Use);
}
<Use>{ID} {
//fprintf(stderr,"using dir %s\n",yytext);
current->name=yytext;
current->fileName = yyFileName;
current->section=Entry::USINGDIR_SEC;
current_root->addSubEntry(current);
current = new Entry;
yy_pop_state();
}
<Use>{ID}/, {
useModuleName=yytext;
}
<Use>,{BS}"ONLY" { BEGIN(UseOnly);
}
<UseOnly>{BS},{BS} {}
<UseOnly>{ID} {
current->name= useModuleName+"::"+yytext;
current->fileName = yyFileName;
current->section=Entry::USINGDECL_SEC;
current_root->addSubEntry(current);
current = new Entry ;
}
<Use,UseOnly>"\n" {
unput(*yytext);
yy_pop_state();
}
/*------ ignore special fortran statements */
<Start,ModuleBody,SubprogBody>^[ \t]*interface({BS_}{ID}({BS}\({BS}[^ \t()]+{BS}\))?)?/{BS}(!|\n) { // handle interface block
if(YY_START == Start)
{
addModule(NULL);
yy_push_state(ModuleBody); //anon program
}
QCString name = yytext;
int index = name.find("interface", 0, FALSE);
index = name.find(QRegExp("[^ \\t]"), index+9);
//printf(stderr,"%s,%d\n",name.data(),index);
if (index!=-1)
name = name.right(name.length()-index);
else // interface without name, must be inside subprog
name = "interface";
addInterface(name);
yy_push_state(InterfaceBody);
startScope(last_entry);
}
<InterfaceBody>^{BS}"end"({BS}"interface"({BS_}{ID})?)?{BS}/(\n|!) {
if (!endScope(current_root))
yyterminate();
yy_pop_state();
}
<InterfaceBody>module{BS}procedure { yy_push_state(YY_START);
BEGIN(ModuleProcedure);
}
<ModuleProcedure>{ID} {
current->section = Entry::FUNCTION_SEC ;
current->name = yytext;
moduleProcedures.append(current);
addCurrentEntry();
}
<ModuleProcedure>"\n" { unput(*yytext);
yy_pop_state();
}
<InterfaceBody>. {}
/*-- Contains handling --*/
<Start>^{BS}{CONTAINS}/({BS}|\n|!) {
if(YY_START == Start)
{
addModule(NULL);
yy_push_state(ModuleBodyContains); //anon program
}
}
<ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(ModuleBodyContains); }
<SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(SubprogBodyContains); }
/*------ module handling ------------------------------------------------------------*/
<Start>module|program{BS_} { //
if(yytext[0]=='m' || yytext[0]=='M')
yy_push_state(Module);
else
yy_push_state(Program);
defaultProtection = Public;
}
<Start,ModuleBody,ModuleBodyContains>^{BS}"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!) { // end module
resolveModuleProcedures(moduleProcedures, current_root);
if (!endScope(current_root))
yyterminate();
defaultProtection = Public;
yy_pop_state();
}
<Module>{ID} {
addModule(yytext, TRUE);
BEGIN(ModuleBody);
}
<Program>{ID} {
addModule(yytext, FALSE);
BEGIN(ModuleBody);
}
/*------- access specification --------------------------------------------------------------------------*/
<ModuleBody>private/{BS}(\n|"!") { defaultProtection = Private; }
<ModuleBody>public/{BS}(\n|"!") { defaultProtection = Public; }
/*------- type definition -------------------------------------------------------------------------------*/
<Start,ModuleBody>"type"({BS_}|({COMMA}{ACCESS_SPEC})) { /* type definition found : TYPE , access-spec::type-name |*/
if(YY_START == Start)
{
addModule(NULL);
yy_push_state(ModuleBody); //anon program
}
yy_push_state(Typedef);
current->protection = defaultProtection;
}
<Typedef>{ACCESS_SPEC} {
QCString type= yytext;
}
<Typedef>{ID} { /* type name found */
//cout << "=========> got typedef " << yytext << ": " << yyLineNr << endl;
current->section = Entry::CLASS_SEC; // was Entry::STRUCT_SEC;
current->spec = Entry::Struct;
current->name = yytext;
/* if type is part of a module, mod name is necessary for output */
if ((current_root) &&
(current_root->section == Entry::CLASS_SEC ||
current_root->section == Entry::NAMESPACE_SEC))
//current_root->section == Entry::INTERFACE_SEC))
{
current->name= current_root->name+"::"+current->name;
}
current->fileName = yyFileName;
current->bodyLine = yyLineNr;
addCurrentEntry();
startScope(last_entry);
BEGIN(TypedefBody);
}
<TypedefBody>^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */
//printf("=========> got typedef end \n");
if (!endScope(current_root))
yyterminate();
yy_pop_state();
}
/*------- module/global/typedef variable ---------------------------------------------------*/
<SubprogBody,SubprogBodyContains>^{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) {
//fprintf(stderr,"1e=========> got end subprog: %s\n", yytext);
/* args is used for parameters in list of functions, argList for
parameters in detailed function descripttion */
//current->args = argListToString(current->argList);
//current->endBodyLine = yyLineNr; // ??? what ist endBodyLine for
if (!endScope(current_root))
yyterminate();
yy_pop_state() ;
}
<Start,ModuleBody,TypedefBody,SubprogBody>{
^{BS}{TYPE_SPEC}/{SEPARATE} {
/* variable declaration starts */
if(YY_START == Start)
{
addModule(NULL);
yy_push_state(ModuleBody); //anon program
}
//fprintf(stderr,"4=========> got variable type: %s\n",yytext);
QCString help=yytext;
help= help.simplifyWhiteSpace();
argType= help;
yy_push_state(AttributeList);
}
^{BS}{PP_ID}{KIND}? { /* check for preprocessor symbol expand to type */
QCString str = yytext;
str = str.stripWhiteSpace();
DefineDict* defines = getFileDefineDict();
QCString name;
int index = str.find("(");
if (index != -1)
name = str.left(index).stripWhiteSpace();
else
name = str;
Define *define = (*defines)[name];
if (define != 0 && isTypeName(define->definition))
{
argType = str;
yy_push_state(AttributeList);
}
else
{
REJECT;
}
}
{ATTR_STMT}/{BS_}{ID} |
{ATTR_STMT}/{BS}"::" {
/* attribute statement starts */
//fprintf(stderr,"5=========> Attribute statement: %s\n", yytext);
QCString tmp = yytext;
currentModifiers |= tmp.stripWhiteSpace();
argType="";
yy_push_state(YY_START);
BEGIN( AttributeList ) ;
}
{ID} {
}
}
<AttributeList>{
{COMMA} {}
{BS} {}
{ATTR_SPEC} { /* update current modifiers */
QCString tmp = yytext;
currentModifiers |= (tmp);
}
"::" { /* end attribute list */
BEGIN( Variable );
}
. { /* unknown attribute, consider variable name */
//cout<<"start variables, unput "<<*yytext<<endl;
unput(*yytext);
BEGIN( Variable );
}
}
<Variable>{BS} {}
<Variable>{ID} { /* parse variable declaration */
//cout << "5=========> got variable: " << argType << "::" << yytext << endl;
/* work around for bug in QCString.replace (QCString works) */
QCString name=yytext;
/* remember attributes for the symbol */
modifiers[current_root][name.lower()] |= currentModifiers;
argName= name;
v_type= V_IGNORE;
if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC)
{ // new variable entry
v_type = V_VARIABLE;
current->section = Entry::VARIABLE_SEC;
current->name = argName;
current->type = argType;
current->fileName = yyFileName;
current->bodyLine = yyLineNr; // used for source reference
addCurrentEntry();
}
else if (!argType.isEmpty())
{ // deklaration of parameter list: add type for corr. parameter
parameter= addFortranParameter(argType,argName,docBlock);
if (parameter) v_type= V_PARAMETER;
// save, it may be function return type
modifiers[current_root][name.lower()].type = argType;
// any accumulated doc for argument should be emptied,
// because it is handled other way and this doc can be
// unexpectedly passed to the next member.
current->doc.resize(0);
current->brief.resize(0);
}
}
<Variable>{ARGS} { /* dimension of the previous entry. */
QCString name(argName);
QCString attr("dimension");
attr += yytext;
modifiers[current_root][name] |= attr;
}
<Variable>{COMMA} {}
<Variable>{BS}"=" { yy_push_state(YY_START);
initializer="";
initializerScope = 0;
BEGIN(Initialization);
}
<Variable>"\n" { currentModifiers = SymbolModifiers();
yy_pop_state(); // end variable deklaration list
yyLineNr++; yyLineNr+=lineCountPrepass; lineCountPrepass=0;
docBlock.resize(0);
}
<Initialization,ArrayInitializer>"(/" { initializer+=yytext;
initializerScope++;
BEGIN(ArrayInitializer); // initializer may contain comma
}
<ArrayInitializer>"/)" { initializer+=yytext;
initializerScope--;
if(initializerScope<=0)
{
initializerScope = 0; // just in case
BEGIN(Initialization);
}
}
<ArrayInitializer>. { initializer+=yytext; }
<Initialization>{COMMA} { yy_pop_state(); // end initialization
if (v_type == V_VARIABLE) last_entry->initializer= initializer;
}
<Initialization>"\n"|"!" { //|
yy_pop_state(); // end initialization
if (v_type == V_VARIABLE) last_entry->initializer= initializer;
unput(*yytext);
}
<Initialization>. { initializer+=yytext; }
/*------ fortran subroutine/function handling ------------------------------------------------------------*/
/* Start is initial condition */
<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}/{SUBPROG}{BS_} {
// TYPE_SPEC is for old function style function result
result= yytext;
result= result.stripWhiteSpace();
extractPrefix(result);
//fprintf(stderr, "===%s\n", (const char*)result);
current->type = result;
yy_push_state(SubprogPrefix);
}
<SubprogPrefix>{BS}{SUBPROG}{BS_} {
// Fortran subroutine or function found
addSubprogram(yytext);
BEGIN(Subprog);
}
<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} {
// Fortran subroutine or function found
result= yytext;
result= result.stripWhiteSpace();
extractPrefix(result);
addSubprogram(result);
yy_push_state(Subprog);
}
<Subprog>{BS} { /* ignore white space */ }
<Subprog>{ID} { current->name = yytext;
//cout << "1a==========> got " << current->type << " " << yytext << " " << yyLineNr << endl;
modifiers[current_root][current->name.lower()].returnName = current->name;
BEGIN(Parameterlist);
}
<Parameterlist>{ARGS} {
//current->type not yet available
QCString arglist= yytext;
//cout << "3=========> got parameterlist " << yytext << endl;
//yyLineNr+= arglist.contains('\n');
//static QRegExp re("&[^\n]*\n");
//arglist = arglist.replace(re,"");
//cout << "3=========> got parameterlist " << arglist << endl;
current->args = arglist;
current->args = removeRedundantWhiteSpace(current->args);
stringToArgumentList(current->args, current->argList);
addCurrentEntry();
startScope(last_entry);
BEGIN(SubprogBody);
}
<Parameterlist>{NOARGS} {
yyLineNr++; yyLineNr+=lineCountPrepass; lineCountPrepass=0;
//printf("3=========> without parameterlist \n");
stringToArgumentList("", current->argList);
addCurrentEntry();
startScope(last_entry);
BEGIN(SubprogBody);
}
<SubprogBody>result{BS}\({BS}{ID} {
result= yytext;
result= result.right(result.length()-result.find("(")-1);
result= result.stripWhiteSpace();
modifiers[current_root->parent()][current_root->name.lower()].returnName = result;
//cout << "=====> got result " << result << endl;
}
/*---- documentation comments --------------------------------------------------------------------*/
<Variable>"!<" { /* backward docu comment (only one line) */
if (v_type != V_IGNORE) {
yy_push_state(YY_START);
current->docLine = yyLineNr;
docBlockJavaStyle = FALSE;
docBlock.resize(0);
docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF");
startCommentBlock(TRUE);
BEGIN(DocBackLine);
}
}
<DocBackLine>.* { // contents of current comment line
docBlock=yytext;
if (v_type == V_VARIABLE)
{
Entry *tmp_entry = current;
current = last_entry; // temporarily switch to the previous entry
handleCommentBlock(docBlock,TRUE);
current=tmp_entry;
}
else if (v_type == V_PARAMETER)
{
parameter->docs=docBlock;
}
yy_pop_state();
}
<Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>"!>" {
yy_push_state(YY_START);
current->docLine = yyLineNr;
docBlockJavaStyle = FALSE;
docBlock.resize(0);
docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF");
startCommentBlock(TRUE);
BEGIN(DocBlock);
//cout << "start DocBlock " << endl;
}
<DocBlock>.* { // contents of current comment line
docBlock+=yytext;
}
<DocBlock>"\n"{BS}"!"(">"|"!"+) { // comment block (next line is also comment line)
docBlock+="\n"; // \n is necessary for lists
yyLineNr++; yyLineNr+=lineCountPrepass; lineCountPrepass=0;
}
<DocBlock>"\n" { // comment block ends at the end of this line
//cout <<"3=========> comment block : "<< docBlock << endl;
unput(*yytext);
handleCommentBlock(docBlock,TRUE);
yy_pop_state();
}
/*------------------------------------------------------------------------------------------------*/
<*>"\n" {
yyLineNr++; yyLineNr+=lineCountPrepass; lineCountPrepass=0;
//if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl;
debugStr="";
}
/*---- error: EOF in wrong state --------------------------------------------------------------------*/
<*><<EOF>> {
if ( include_stack_ptr <= 0 ) {
if (YY_START!=INITIAL && YY_START!=Start) {
//fprintf(stderr,"==== Error: EOF reached in wrong state (end missing)");
scanner_abort();
}
yyterminate();
} else {
popBuffer();
}
}
<*>. {
//debugStr+=yytext;
//printf("I:%c\n", *yytext);
} // ignore remaining text
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
%%
//----------------------------------------------------------------------------
static void extractPrefix(QCString &text) {
int prefixIndex = 0;
int curIndex = 0;
bool cont = TRUE;
const char* pre[] = {"RECURSIVE","PURE","ELEMENTAL"};
while(cont)
{
cont = FALSE;
for(unsigned int i=0; i<3; i++)
{
if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0)
{
text.remove(0,strlen(pre[i]));
text.stripWhiteSpace();
cont = TRUE;
}
}
}
}
static int getAmpersandAtTheStart(const char *buf, int length)
{
for(int i=0; i<length; i++) {
switch(buf[i]) {
case ' ':
case '\t':
break;
case '&':
return i;
default:
return -1;
}
}
return -1;
}
/* Returns ampersand index, comment start index or -1 if neither exist.*/
static int getAmpOrExclAtTheEnd(const char *buf, int length)
{
// Avoid ampersands in string and comments
int parseState = Start;
char quoteSymbol = 0;
int ampIndex = -1;
int commentIndex = -1;
for(int i=0; i<length && parseState!=Comment; i++)
{
// When in string, skip backslashes
// Legacy code, not sure whether this is correct?
if(parseState==String)
{
if(buf[i]=='\\') i++;
}
switch(buf[i])
{
case '\'':
case '"':
// Close string, if quote symbol matches.
// Quote symbol is set iff parseState==String
if(buf[i]==quoteSymbol)
{
parseState = Start;
quoteSymbol = 0;
}
// Start new string, if not already in string or comment
else if(parseState==Start)
{
parseState = String;
quoteSymbol = buf[i];
}
ampIndex = -1; // invalidate prev ampersand
break;
case '!':
// When in string or comment, ignore exclamation mark
if(parseState==Start)
{
parseState = Comment;
commentIndex = i;
}
break;
case ' ': // ignore whitespace
case '\t':
case '\n': // this may be at the end of line
break;
case '&':
ampIndex = i;
break;
default:
ampIndex = -1; // invalidate prev ampersand
}
}
if (ampIndex>=0)
return ampIndex;
else
return commentIndex;
}
/* Although comments at the end of continuation line are grabbed by this function,
* we still do not know how to use them later in parsing.
*/
void truncatePrepass(int index)
{
int length = inputStringPrepass.length();
for (int i=index+1; i<length; i++) {
if (inputStringPrepass[i]=='!') { // save comment
//printf("-----SAVE----- %d:%s", i, (const char*)inputStringPrepass.right(length-i));
struct CommentInPrepass *c=new CommentInPrepass(index, inputStringPrepass.right(length-i));
comments.append(c);
}
}
inputStringPrepass.truncate(index);
}
// simplified way to know if this is fixed form
// duplicate in fortrancode.l
static bool recognizeFixedForm(const char* contents)
{
int column=0;
bool skipLine=FALSE;
for(int i=0;;i++) {
column++;
switch(contents[i]) {
case '\n':
column=0;
skipLine=FALSE;
break;
case ' ':
break;
case '\000':
return FALSE;
case 'C':
case 'c':
case '*':
if(column==1) return TRUE;
if(skipLine) break;
return FALSE;
case '!':
if(column>1 && column<7) return FALSE;
skipLine=TRUE;
break;
default:
if(skipLine) break;
if(column==7) return TRUE;
return FALSE;
}
}
return FALSE;
}
/* This function assumes that contents has at least size=length+1 */
static void insertCharacter(char *contents, int length, int pos, char c)
{
// shift tail by one character
for(int i=length; i>pos; i--)
contents[i]=contents[i-1];
// set the character
contents[pos] = c;
}
/* change comments and bring line continuation character to previous line */
static const char* prepassFixedForm(const char* contents)
{
int column=0;
int prevLineLength=0;
int prevLineAmpOrExclIndex=-1;
bool emptyLabel=TRUE;
int newContentsSize = strlen(contents)+2; // \000 and one spare character (to avoid reallocation)
char* newContents = (char*)malloc(newContentsSize);
for(int i=0, j=0;;i++,j++) {
if(j>=newContentsSize-1) { // check for one spare character, which may be eventually used below (by &)
newContents = (char*)realloc(newContents, newContentsSize+1000);
newContentsSize = newContentsSize+1000;
}
column++;
char c = contents[i];
switch(c) {
case '\n':
prevLineLength=column;
prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength);
column=0;
emptyLabel=TRUE;
newContents[j]=c;
break;
case ' ':
newContents[j]=c;
break;
case '\000':
newContents[j]='\000';
return newContents;
case 'C':
case 'c':
case '*':
emptyLabel=FALSE;
if(column==1)
newContents[j]='!';
else
newContents[j]=c;
break;
default:
if(column==6 && emptyLabel) { // continuation
newContents[j]=' ';
if(prevLineAmpOrExclIndex==-1) { // add & just before end of previous line
insertCharacter(newContents, j+1, (j+1)-6-1, '&');
j++;
} else { // add & just before end of previous line comment
insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex, '&');
j++;
}
} else {
newContents[j]=c;
emptyLabel=FALSE;
}
break;
}
}
return newContents;
}
static void pushBuffer(QCString& buffer)
{
if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
{
fprintf( stderr, "Stack buffers nested too deeply" );
exit( 1 );
}
include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
yy_switch_to_buffer(yy_scan_string(buffer));
//fprintf(stderr, "--PUSH--%s", (const char *)buffer);
buffer = NULL;
}
static void popBuffer() {
//fprintf(stderr, "--POP--");
include_stack_ptr --;
yy_delete_buffer( YY_CURRENT_BUFFER );
yy_switch_to_buffer( include_stack[include_stack_ptr] );
}
/** used to copy entry to an interface module procedure */
static void copyEntry(Entry *dest, Entry *src)
{
dest->type = src->type;
dest->fileName = src->fileName;
dest->bodyLine = src->bodyLine;
dest->args = src->args;
dest->argList = new ArgumentList(*src->argList);
}
/** fill empty interface module procedures with info from
corresponding module subprogs
@TODO: handle procedures in used modules
*/
void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root)
{
if (moduleProcedures.isEmpty()) return;
EntryListIterator eli1(moduleProcedures);
// for all module procedures
for (Entry *ce1; (ce1=eli1.current()); ++eli1)
{
// check all entries in this module
EntryListIterator eli2(*current_root->children());
for (Entry *ce2; (ce2=eli2.current()); ++eli2)
{
if (ce1->name == ce2->name)
{
copyEntry(ce1, ce2);
}
} // for procedures in current module
} // for all interface module procedures
moduleProcedures.clear();
}
static bool isTypeName(QCString name)
{
name = name.lower();
return name=="integer" || name == "real" ||
name=="complex" || name == "logical";
}
/*! Extracts string which resides within parentheses of provided string. */
static QCString extractFromParens(const QCString name)
{
QCString extracted = name;
int start = extracted.find("(");
if (start != -1)
{
extracted.remove(0, start+1);
}
int end = extracted.findRev(")");
if (end != -1)
{
int length = extracted.length();
extracted.remove(end, length);
}
extracted = extracted.stripWhiteSpace();
return extracted;
}
/*! Adds passed modifiers to these modifiers.*/
SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs)
{
if (mdfs.protection!=NONE_P) protection = mdfs.protection;
if (mdfs.direction!=NONE_D) direction = mdfs.direction;
optional |= mdfs.optional;
if (!mdfs.dimension.isNull()) dimension = mdfs.dimension;
allocatable |= mdfs.allocatable;
external |= mdfs.external;
intrinsic |= mdfs.intrinsic;
parameter |= mdfs.parameter;
pointer |= mdfs.pointer;
target |= mdfs.target;
save |= mdfs.save;
return *this;
}
/*! Extracts and adds passed modifier to these modifiers.*/
SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString)
{
mdfString = mdfString.lower();
SymbolModifiers newMdf;
if (mdfString.find("dimension")==0)
{
newMdf.dimension=mdfString;
}
else if (mdfString.contains("intent"))
{
QCString tmp = extractFromParens(mdfString);
bool isin = tmp.contains("in");
bool isout = tmp.contains("out");
if (isin && isout) newMdf.direction = SymbolModifiers::INOUT;
else if (isin) newMdf.direction = SymbolModifiers::IN;
else if (isout) newMdf.direction = SymbolModifiers::OUT;
}
else if (mdfString=="public")
{
newMdf.protection = SymbolModifiers::PUBLIC;
}
else if (mdfString=="private")
{
newMdf.protection = SymbolModifiers::PRIVATE;
}
else if (mdfString=="optional")
{
newMdf.optional = TRUE;
}
else if (mdfString=="allocatable")
{
newMdf.allocatable = TRUE;
}
else if (mdfString=="external")
{
newMdf.external = TRUE;
}
else if (mdfString=="intrinsic")
{
newMdf.intrinsic = TRUE;
}
else if (mdfString=="parameter")
{
newMdf.parameter = TRUE;
}
else if (mdfString=="pointer")
{
newMdf.pointer = TRUE;
}
else if (mdfString=="target")
{
newMdf.target = TRUE;
}
else if (mdfString=="save")
{
newMdf.save = TRUE;
}
(*this) |= newMdf;
return *this;
}
/*! For debugging purposes. */
//ostream& operator<<(ostream& out, const SymbolModifiers& mdfs)
//{
// out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<<
// ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<<
// ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic;
//
// return out;
//}
/*! Find argument with given name in \a subprog entry. */
static Argument *findArgument(Entry* subprog, QCString name, bool byTypeName = FALSE)
{
QCString cname(name.lower());
for (unsigned int i=0; i<subprog->argList->count(); i++)
{
Argument *arg = subprog->argList->at(i);
if ((!byTypeName && arg->name.lower() == cname) ||
(byTypeName && arg->type.lower() == cname)
)
{
return arg;
}
}
return 0;
}
/*! Find function with given name in \a entry. */
#if 0
static Entry *findFunction(Entry* entry, QCString name)
{
QCString cname(name.lower());
EntryListIterator eli(*entry->children());
Entry *ce;
for (;(ce=eli.current());++eli)
{
if (ce->section != Entry::FUNCTION_SEC)
continue;
if (ce->name.lower() == cname)
return ce;
}
return 0;
}
#endif
/*! Apply modifiers stored in \a mdfs to the \a typeName string. */
static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs)
{
if (!mdfs.dimension.isNull())
{
typeName += ",";
typeName += mdfs.dimension;
}
if (mdfs.direction!=SymbolModifiers::NONE_D)
{
typeName += ",";
typeName += directionStrs[mdfs.direction];
}
if (mdfs.optional)
{
typeName += ",";
typeName += "optional";
}
if (mdfs.allocatable)
{
typeName += ",";
typeName += "allocatable";
}
if (mdfs.external)
{
typeName += ",";
typeName += "external";
}
if (mdfs.intrinsic)
{
typeName += ",";
typeName += "intrinsic";
}
if (mdfs.parameter)
{
typeName += ",";
typeName += "parameter";
}
if (mdfs.pointer)
{
typeName += ",";
typeName += "pointer";
}
if (mdfs.target)
{
typeName += ",";
typeName += "target";
}
if (mdfs.save)
{
typeName += ",";
typeName += "save";
}
return typeName;
}
/*! Apply modifiers stored in \a mdfs to the \a arg argument. */
static void applyModifiers(Argument *arg, SymbolModifiers& mdfs)
{
QCString tmp = arg->type;
arg->type = applyModifiers(tmp, mdfs);
}
/*! Apply modifiers stored in \a mdfs to the \a ent entry. */
static void applyModifiers(Entry *ent, SymbolModifiers& mdfs)
{
QCString tmp = ent->type;
ent->type = applyModifiers(tmp, mdfs);
if (mdfs.protection == SymbolModifiers::PUBLIC)
ent->protection = Public;
else if (mdfs.protection == SymbolModifiers::PRIVATE)
ent->protection = Private;
}
/*! Starts the new scope in fortran program. Consider using this function when
* starting module, interface, function or other program block.
* \see endScope()
*/
static void startScope(Entry *scope)
{
//cout<<"start scope: "<<scope->name<<endl;
current_root= scope; /* start substructure */
QMap<QCString,SymbolModifiers> mdfMap;
modifiers.insert(scope, mdfMap);
}
/*! Ends scope in fortran program: may update subprogram arguments or module variable attributes.
* \see startScope()
*/
static bool endScope(Entry *scope, bool isGlobalRoot)
{
//cout<<"end scope: "<<scope->name<<endl;
if (current_root->parent() || isGlobalRoot)
{
current_root= current_root->parent(); /* end substructure */
}
else
{
fprintf(stderr,"parse error in end <scopename>");
scanner_abort();
return FALSE;
}
// update variables or subprogram arguments with modifiers
QMap<QCString,SymbolModifiers>& mdfsMap = modifiers[scope];
if (scope->section == Entry::FUNCTION_SEC)
{
// iterate all symbol modifiers of the scope
for (QMap<QCString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++)
{
//cout<<it.key()<<": "<<it.data()<<endl;
Argument *arg = findArgument(scope, it.key());
if (arg)
applyModifiers(arg, it.data());
}
// find return type for function
//cout<<"RETURN NAME "<<modifiers[current_root][scope->name.lower()].returnName<<endl;
QCString returnName = modifiers[current_root][scope->name.lower()].returnName.lower();
if (modifiers[scope].contains(returnName))
{
scope->type = modifiers[scope][returnName].type; // returning type works
applyModifiers(scope, modifiers[scope][returnName]); // returning array works
}
}
if (scope->section == Entry::CLASS_SEC)
{ // was INTERFACE_SEC
if (scope->parent()->section == Entry::FUNCTION_SEC)
{ // interface within function
// iterate functions of interface and
// try to find types for dummy(ie. argument) procedures.
//cout<<"Search in "<<scope->name<<endl;
EntryListIterator eli(*scope->children());
Entry *ce;
for (;(ce=eli.current());++eli)
{
if (ce->section != Entry::FUNCTION_SEC)
continue;
Argument *arg = findArgument(scope->parent(), ce->name, TRUE);
if (arg != 0)
{
// set type of dummy procedure argument to interface
arg->name = arg->type;
arg->type = scope->name;
}
}
}
}
if (scope->section!=Entry::FUNCTION_SEC)
{ // not function section
// iterate variables: get and apply modifiers
EntryListIterator eli(*scope->children());
Entry *ce;
for (;(ce=eli.current());++eli)
{
if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC)
continue;
//cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl;
if (mdfsMap.contains(ce->name.lower()))
applyModifiers(ce, mdfsMap[ce->name.lower()]);
}
}
// clear all modifiers of the scope
modifiers.remove(scope);
return TRUE;
}
//! Return full name of the entry. Sometimes we must combine several names recursively.
static QCString getFullName(Entry *e)
{
QCString name = e->name;
if (e->section == Entry::CLASS_SEC // || e->section == Entry::INTERFACE_SEC
|| !e->parent() || e->parent()->name.isEmpty())
return name;
return getFullName(e->parent())+"::"+name;
}
static int yyread(char *buf,int max_size)
{
int c=0;
while ( c < max_size && inputString[inputPosition] )
{
*buf = inputString[inputPosition++] ;
c++; buf++;
}
return c;
}
static void initParser()
{
last_entry = 0;
}
static void initEntry()
{
current->protection = defaultProtection ;
current->mtype = mtype;
current->virt = virt;
current->stat = gstat;
initGroupInfo(current);
}
/**
adds current entry to current_root and creates new current
*/
static void addCurrentEntry()
{
//printf("===Adding entry %s to %s\n", current->name.data(), current_root->name.data());
current_root->addSubEntry(current);
last_entry = current;
current = new Entry ;
initEntry();
}
static int max(int a, int b) {return a>b?a:b;}
static void addModule(const char *name, bool isModule)
{
//fprintf(stderr, "0=========> got module %s\n", name);
if (isModule)
current->section = Entry::NAMESPACE_SEC;
else
current->section = Entry::FUNCTION_SEC;
if (name!=NULL)
{
current->name = name;
}
else
{
QCString fname = yyFileName;
int index = max(fname.findRev('/'), fname.findRev('\\'));
fname = fname.right(fname.length()-index-1);
fname = fname.prepend("__").append("__");
current->name = fname;
}
current->type = "program";
current->fileName = yyFileName;
current->bodyLine = yyLineNr; // used for source reference
current->protection = Public ;
addCurrentEntry();
startScope(last_entry);
}
static void addSubprogram(const char *text)
{
//fprintf(stderr,"1=========> got subprog, type: %s\n",text);
current->section = Entry::FUNCTION_SEC ;
QCString subtype = text; subtype=subtype.lower().stripWhiteSpace();
if (!current->type) current->type = subtype;
current->fileName = yyFileName;
current->bodyLine = yyLineNr; // used for source reference
current->startLine = -1; // ??? what is startLine for?
current->args.resize(0);
current->argList->clear();
docBlock.resize(0);
}
/*! 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.
*/
static void addInterface(QCString name)
{
current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC;
current->spec = Entry::Interface;
current->name = name;
/* if type is part of a module, mod name is necessary for output */
if ((current_root) &&
(current_root->section == Entry::CLASS_SEC ||
current_root->section == Entry::NAMESPACE_SEC))
{
current->name= current_root->name+"::"+current->name;
}
if ((current_root) &&
(current_root->section == Entry::FUNCTION_SEC))
{
current->name = getFullName(current_root) + "__" + QCString(current->name);
}
current->fileName = yyFileName;
current->bodyLine = yyLineNr;
addCurrentEntry();
}
//-----------------------------------------------------------------------------
/*! Update the argument \a name with additional \a type info.
*/
static Argument *addFortranParameter(const QCString &type,const QCString &name, const QCString docs)
{
//cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<endl;
Argument *ret = 0;
if (current_root->argList==0) return 0;
ArgumentListIterator ali(*current_root->argList);
Argument *a;
for (ali.toFirst();(a=ali.current());++ali)
{
if (a->type.lower()==name.lower())
{
ret=a;
//cout << "addParameter found: " << type << " , " << name << endl;
a->type=type.stripWhiteSpace();
a->name=name.stripWhiteSpace();
if (!docs.isNull())
a->docs = docs;
break;
}
} // for
return ret;
}
//----------------------------------------------------------------------------
static void startCommentBlock(bool brief)
{
if (brief)
{
current->briefFile = yyFileName;
current->briefLine = yyLineNr;
}
else
{
current->docFile = yyFileName;
current->docLine = yyLineNr;
}
}
//----------------------------------------------------------------------------
static void handleCommentBlock(const QCString &doc,bool brief)
{
docBlockInBody = FALSE;
bool needsEntry = FALSE;
static bool hideInBodyDocs = Config_getBool("HIDE_IN_BODY_DOCS");
int position=0;
if (docBlockInBody && hideInBodyDocs) return;
//fprintf(stderr,"call parseCommentBlock [%s]\n",doc.data());
int lineNr = brief ? current->briefLine : current->docLine;
while (parseCommentBlock(
g_thisParser,
docBlockInBody ? last_entry : current,
doc, // text
yyFileName, // file
lineNr,
docBlockInBody ? FALSE : brief,
docBlockInBody ? FALSE : docBlockJavaStyle,
docBlockInBody,
defaultProtection,
position,
needsEntry
))
{
//fprintf(stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry);
if (needsEntry) addCurrentEntry();
}
//fprintf(stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry);
if (needsEntry) addCurrentEntry();
}
//----------------------------------------------------------------------------
static int level=0;
static void debugCompounds(Entry *rt) // print Entry structure (for debugging)
{
level++;
printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine);
EntryListIterator eli(*rt->children());
Entry *ce;
for (;(ce=eli.current());++eli)
{
debugCompounds(ce);
}
level--;
}
static void parseMain(const char *fileName,const char *fileBuf,Entry *rt)
{
initParser();
defaultProtection = Public;
inputString = fileBuf;
inputPosition = 0;
inputStringPrepass = NULL;
inputPositionPrepass = 0;
//anonCount = 0; // don't reset per file
mtype = Method;
gstat = FALSE;
virt = Normal;
current_root = rt;
global_root = rt;
inputFile.setName(fileName);
if (inputFile.open(IO_ReadOnly))
{
isFixedForm = recognizeFixedForm(fileBuf);
if (isFixedForm) {
printf("Prepassing fixed form of %s\n", yyFileName.data());
//printf("---strlen=%d\n", strlen(fileBuf));
//clock_t start=clock();
inputString = prepassFixedForm(fileBuf);
//clock_t end=clock();
//printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC);
}
yyLineNr= 1 ;
yyFileName = fileName;
msg("Parsing file %s...\n",yyFileName.data());
startScope(rt); // implies current_root = rt
initParser();
groupEnterFile(yyFileName,yyLineNr);
current = new Entry;
current->name = yyFileName;
current->section = Entry::SOURCE_SEC;
current_root->addSubEntry(current);
file_root = current;
current = new Entry;
fscanYYrestart( fscanYYin );
{
BEGIN( Start );
}
fscanYYlex();
groupLeaveFile(yyFileName,yyLineNr);
endScope(current_root, TRUE); // TRUE - global root
//debugCompounds(rt); //debug
rt->program.resize(0);
delete current; current=0;
moduleProcedures.clear();
if (isFixedForm) {
free((char*)inputString);
inputString=NULL;
}
inputFile.close();
}
}
//----------------------------------------------------------------------------
void FortranLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root)
{
g_thisParser = this;
::parseMain(fileName,fileBuf,root);
}
void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
const char * scopeName,
const QCString & input,
bool isExampleBlock,
const char * exampleName,
FileDef * fileDef,
int startLine,
int endLine,
bool inlineFragment,
MemberDef *memberDef
)
{
::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
fileDef,startLine,endLine,inlineFragment,memberDef);
}
bool FortranLanguageScanner::needsPreprocessing(const QCString &extension)
{
(void)extension;
return TRUE;
}
void FortranLanguageScanner::resetCodeParserState()
{
::resetFortranCodeParserState();
}
void FortranLanguageScanner::parsePrototype(const char *text)
{
(void)text;
}
static void scanner_abort()
{
fprintf(stderr,"********************************************************************\n");
fprintf(stderr,"Error in file %s line: %d, state: %d\n",yyFileName.data(),yyLineNr,YY_START);
fprintf(stderr,"********************************************************************\n");
EntryListIterator eli(*global_root->children());
Entry *ce;
bool start=FALSE;
for (;(ce=eli.current());++eli)
{
if (ce == file_root) start=TRUE;
if (start) ce->reset();
}
// dummy call to avoid compiler warning
(void)yy_top_state();
return;
//exit(-1);
}
//----------------------------------------------------------------------------
#if !defined(YY_FLEX_SUBMINOR_VERSION)
//----------------------------------------------------------------------------
extern "C" { // some bogus code to keep the compiler happy
void fscannerYYdummy() { yy_flex_realloc(0,0); }
}
#endif