Contribution of a new version of ORB and CXX DITA plug-in bug 1461 bug 1621 bug 1962
/******************************************************************************
*
* Parser for syntax hightlighting and references 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.
*
*/
/**
@todo - continutation lines not always recognized
- merging of use-statements with same module name and different only-names
- rename part of use-statement
- links to interface functions
- references to variables
**/
%{
/*
* includes
*/
#include "qtbc.h"
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <qregexp.h>
#include <qdir.h>
#include <qstringlist.h>
#include "entry.h"
#include "doxygen.h"
#include "message.h"
#include "outputlist.h"
#include "util.h"
#include "membername.h"
#include "searchindex.h"
#include "defargs.h"
#define YY_NEVER_INTERACTIVE 1
#define YY_NO_TOP_STATE 1
//--------------------------------------------------------------------------------
/**
data of an use-statement
*/
class UseEntry
{
public:
QCString module; // just for debug
QStringList onlyNames; /* entries of the ONLY-part */
};
/**
module name -> list of ONLY/remote entries
(module name = name of the module, which can be accessed via use-directive)
*/
class UseSDict : public SDict<UseEntry>
{
public:
UseSDict() : SDict<UseEntry>(17) {}
};
/**
Contains names of used modules and names of local variables.
*/
class Scope
{
public:
QStringList useNames; //!< contains names of used modules
QDict<void> localVars; //!< contains names of local variables
Scope() : localVars(7, FALSE /*caseSensitive*/) {}
};
/*===================================================================*/
/*
* statics
*/
static QCString docBlock; //!< contents of all lines of a documentation block
static QCString currentModule=0; //!< name of the current enclosing module
static UseSDict *useMembers= new UseSDict; //!< info about used modules
static UseEntry *useEntry = 0; //!< current use statement info
static QList<Scope> scopeStack;
// static QStringList *currentUseNames= new QStringList; //! contains names of used modules of current program unit
static QCString str=""; //!> contents of fortran string
static CodeOutputInterface * g_code;
// TODO: is this still needed? if so, make it work
static QCString g_parmType;
static QCString g_parmName;
static const char * g_inputString; //!< the code fragment as text
static int g_inputPosition; //!< read offset during parsing
static int g_inputLines; //!< number of line in the code fragment
static int g_yyLineNr; //!< current line number
static bool g_needsTermination;
static bool g_isFixedForm;
static bool g_insideBody; //!< inside subprog/program body? => create links
static const char * g_currentFontClass;
static bool g_exampleBlock;
static QCString g_exampleName;
static QCString g_exampleFile;
static FileDef * g_sourceFileDef;
static Definition * g_currentDefinition;
static MemberDef * g_currentMemberDef;
static bool g_includeCodeFragment;
static char stringStartSymbol; // single or double quote
// count in variable declaration to filter out
// declared from referenced names
static int bracketCount = 0;
// simplified way to know if this is fixed form
// duplicate in fortranscanner.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;
}
static void endFontClass()
{
if (g_currentFontClass)
{
g_code->endFontClass();
g_currentFontClass=0;
}
}
static void startFontClass(const char *s)
{
endFontClass();
g_code->startFontClass(s);
g_currentFontClass=s;
}
static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="")
{
if (Doxygen::searchIndex)
{
Doxygen::searchIndex->setCurrentDoc(name,base,anchor);
}
}
static void addToSearchIndex(const char *text)
{
if (Doxygen::searchIndex)
{
Doxygen::searchIndex->addWord(text,FALSE);
}
}
/*! start a new line of code, inserting a line number if g_sourceFileDef
* is TRUE. If a definition starts at the current line, then the line
* number is linked to the documentation of that definition.
*/
static void startCodeLine()
{
if (g_sourceFileDef)
{
//QCString lineNumber,lineAnchor;
//lineNumber.sprintf("%05d",g_yyLineNr);
//lineAnchor.sprintf("l%05d",g_yyLineNr);
Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
//printf("startCodeLine %d d=%s\n", g_yyLineNr,d ? d->name().data() : "<null>");
if (!g_includeCodeFragment && d)
{
g_currentDefinition = d;
g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
g_insideBody = FALSE;
g_parmType.resize(0);
g_parmName.resize(0);
QCString lineAnchor;
lineAnchor.sprintf("l%05d",g_yyLineNr);
if (g_currentMemberDef)
{
g_code->writeLineNumber(g_currentMemberDef->getReference(),
g_currentMemberDef->getOutputFileBase(),
g_currentMemberDef->anchor(),g_yyLineNr);
setCurrentDoc(
g_currentMemberDef->qualifiedName(),
g_sourceFileDef->getSourceFileBase(),
lineAnchor);
}
else if (d->isLinkableInProject())
{
g_code->writeLineNumber(d->getReference(),
d->getOutputFileBase(),
0,g_yyLineNr);
setCurrentDoc(
d->qualifiedName(),
g_sourceFileDef->getSourceFileBase(),
lineAnchor);
}
}
else
{
g_code->writeLineNumber(0,0,0,g_yyLineNr);
}
}
g_code->startCodeLine();
if (g_currentFontClass)
{
g_code->startFontClass(g_currentFontClass);
}
}
static void endFontClass();
static void endCodeLine()
{
endFontClass();
g_code->endCodeLine();
}
/*! write a code fragment `text' that may span multiple lines, inserting
* line numbers for each line.
*/
static void codifyLines(char *text)
{
//printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text);
char *p=text,*sp=p;
char c;
bool done=FALSE;
while (!done)
{
sp=p;
while ((c=*p++) && c!='\n') { }
if (c=='\n')
{
g_yyLineNr++;
*(p-1)='\0';
g_code->codify(sp);
endCodeLine();
if (g_yyLineNr<g_inputLines)
{
startCodeLine();
}
}
else
{
g_code->codify(sp);
done=TRUE;
}
}
}
static void codifyLines(QCString str)
{
char *tmp= (char *) malloc(str.length()+1);
strcpy(tmp, str);
codifyLines(tmp);
free(tmp);
}
/*! writes a link to a fragment \a text that may span multiple lines, inserting
* line numbers for each line. If \a text contains newlines, the link will be
* split into multiple links with the same destination, one for each line.
*/
static void writeMultiLineCodeLink(CodeOutputInterface &ol,
const char *ref,const char *file,
const char *anchor,const char *text)
{
bool done=FALSE;
char *p=(char *)text;
while (!done)
{
char *sp=p;
char c;
while ((c=*p++) && c!='\n') { }
if (c=='\n')
{
g_yyLineNr++;
*(p-1)='\0';
//printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
ol.writeCodeLink(ref,file,anchor,sp,0);
endCodeLine();
if (g_yyLineNr<g_inputLines)
{
startCodeLine();
}
}
else
{
//printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
ol.writeCodeLink(ref,file,anchor,sp,0);
done=TRUE;
}
}
}
/**
generates dictionay entries that are used if REFERENCED_BY_RELATION ... options are set
(e.g. the "referenced by ..." list after the function documentation)
*/
static void addDocCrossReference(MemberDef *src, MemberDef *dst)
{
if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types
//printf("======= addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data());
if ((Config_getBool("REFERENCED_BY_RELATION") || Config_getBool("CALLER_GRAPH")) &&
(src->isFunction()))
{
dst->addSourceReferencedBy(src);
}
if ((Config_getBool("REFERENCES_RELATION") || Config_getBool("CALL_GRAPH")) && (src->isFunction()))
{
src->addSourceReferences(dst);
}
}
//-------------------------------------------------------------------------------
/**
searches for definition of a type
@param tname the name of the type
@param moduleName name of enclosing module or null, if global entry
@param cd the entry, if found or null
@param useDict dictionary of data of USE-statement
@returns true, if type is found
*/
static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
ClassDef *&cd, UseSDict *usedict=0)
{
if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
//cout << "=== search for type: " << tname << endl;
// search for type
if ((cd=Doxygen::classSDict->find(tname)))
{
//cout << "=== type found in global module" << endl;
return TRUE;
}
else if (moduleName && (cd= Doxygen::classSDict->find(moduleName+"::"+tname)))
{
//cout << "=== type found in local module" << endl;
return TRUE;
}
else
{
UseEntry *use;
for (UseSDict::Iterator di(*usedict); (use=di.current()); ++di)
if ((cd= Doxygen::classSDict->find(use->module+"::"+tname)))
{
//cout << "=== type found in used module" << endl;
return TRUE;
}
}
return FALSE;
}
/**
searches for definition of function memberName
@param memberName the name of the function/variable
@param moduleName name of enclosing module or null, if global entry
@param md the entry, if found or null
@param usedict array of data of USE-statement
@returns true, if found
*/
static bool getFortranDefs(const QCString &memberName, const QCString &moduleName,
MemberDef *&md, UseSDict *usedict=0)
{
if (memberName.isEmpty()) return FALSE; /* empty name => nothing to link */
// look in local variables
for (Scope *scope=scopeStack.last(); scope!=NULL; scope=scopeStack.prev())
{
if(scope->localVars.find(memberName))
return FALSE;
}
// search for function
MemberName *mn = Doxygen::functionNameSDict->find(memberName);
if (mn) // name is known
{
MemberListIterator mli(*mn);
for (mli.toFirst();(md=mli.current());++mli) // all found functions with given name
{
FileDef *fd=md->getFileDef();
GroupDef *gd=md->getGroupDef();
//cout << "found link with same name: " << fd->fileName() << " " << memberName;
//if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl;
if ((gd && gd->isLinkable()) || (fd && fd->isLinkable()))
{
NamespaceDef *nspace= md->getNamespaceDef();
if (nspace == 0)
{ // found function in global scope
return TRUE;
}
else if (moduleName == nspace->name())
{ // found in local scope
return TRUE;
}
else
{ // else search in used modules
QCString moduleName= nspace->name();
UseEntry *ue= usedict->find(moduleName);
if (ue)
{
// check if only-list exists and if current entry exists is this list
QStringList &only= ue->onlyNames;
if (only.isEmpty())
{
//cout << " found in module " << moduleName << " entry " << memberName << endl;
return TRUE; // whole module used
}
else
{
for ( QStringList::Iterator it = only.begin(); it != only.end(); ++it)
{
//cout << " search in only: " << moduleName << ":: " << memberName << "==" << (*it)<< endl;
if (memberName == (QCString)(*it))
return TRUE; // found in ONLY-part of use list
}
}
}
}
} // if linkable
} // for
}
return FALSE;
}
/**
gets the link to a generic procedure which depends not on the name, but on the parameter list
@todo implementation
*/
static bool getGenericProcedureLink(const ClassDef *cd,
const char *memberText,
CodeOutputInterface &ol)
{
(void)cd;
(void)memberText;
(void)ol;
return FALSE;
}
static bool getLink(UseSDict *usedict, // dictonary with used modules
const char *memberText, // exact member text
CodeOutputInterface &ol,
const char *text)
{
MemberDef *md;
QCString memberName= removeRedundantWhiteSpace(memberText);
if (getFortranDefs(memberName, currentModule, md, usedict) && md->isLinkable())
{
//if (md->isVariable()) return FALSE; // variables aren't handled yet
Definition *d = md->getOuterScope()==Doxygen::globalScope ?
md->getBodyDef() : md->getOuterScope();
if (md->getGroupDef()) d = md->getGroupDef();
if (d && d->isLinkable())
{
if (g_currentDefinition && g_currentMemberDef && md!=g_currentMemberDef && g_insideBody)
{
addDocCrossReference(g_currentMemberDef,md);
}
ol.linkableSymbol(g_yyLineNr,md->name(),md,
g_currentMemberDef ? g_currentMemberDef : g_currentDefinition);
writeMultiLineCodeLink(ol,md->getReference(),
md->getOutputFileBase(),
md->anchor(),
text ? text : memberText);
addToSearchIndex(text ? text : memberText);
return TRUE;
}
}
return FALSE;
}
static void generateLink(CodeOutputInterface &ol, char *lname)
{
ClassDef *cd=0;
// check if lname is a linkable type or interface
if ( (getFortranTypeDefs(lname, currentModule, cd, useMembers)) && cd->isLinkable() )
{
if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) &&
(getGenericProcedureLink(cd, lname, ol)) )
{
//cout << "=== generic procedure resolved" << endl;
}
else
{ // write type or interface link
ol.linkableSymbol(g_yyLineNr, lname, cd, g_currentMemberDef?g_currentMemberDef:g_currentDefinition);
writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),0,lname);
addToSearchIndex(lname);
}
}
// check for function/variable
else if (getLink(useMembers, lname, ol, lname))
{
//cout << "=== found link for " << lname << endl;
}
else
{
// nothing found, just write out the word
ol.linkableSymbol(g_yyLineNr, lname, 0, g_currentMemberDef?g_currentMemberDef:g_currentDefinition);
//startFontClass("charliteral"); //test
codifyLines(lname);
//endFontClass(); //test
addToSearchIndex(lname);
}
}
/*! counts the number of lines in the input */
static int countLines()
{
const char *p=g_inputString;
char c;
int count=1;
while ((c=*p))
{
p++ ;
if (c=='\n') count++;
}
if (p>g_inputString && *(p-1)!='\n')
{ // last line does not end with a \n, so we add an extra
// line and explicitly terminate the line after parsing.
count++,
g_needsTermination=TRUE;
}
return count;
}
//----------------------------------------------------------------------------
/** start scope */
void startScope()
{
// fprintf(stderr, "===> startScope %s",yytext);
Scope *scope = new Scope;
scopeStack.append(scope);
}
/** end scope */
void endScope()
{
// fprintf(stderr,"===> endScope %s",yytext);
if (scopeStack.isEmpty())
{
fprintf(stderr,"WARNING: fortrancode.l: stack empty!");
return;
//exit(-1);
}
Scope *scope = scopeStack.getLast();
scopeStack.removeLast();
for ( QStringList::Iterator it = scope->useNames.begin(); it != scope->useNames.end(); ++it)
{
useMembers->remove(*it);
}
delete scope;
}
void addUse(QString moduleName)
{
if (!scopeStack.isEmpty())
scopeStack.last()->useNames.append(moduleName);
}
void addLocalVar(QString varName)
{
if (!scopeStack.isEmpty())
scopeStack.last()->localVars.insert(varName, (void*)1);
}
//----------------------------------------------------------------------------
/* -----------------------------------------------------------------*/
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
static int yyread(char *buf,int max_size)
{
int c=0;
while( c < max_size && g_inputString[g_inputPosition] )
{
*buf = g_inputString[g_inputPosition++] ;
c++; buf++;
}
return c;
}
%}
IDSYM [a-z_A-Z0-9]
ID [a-z_A-Z]+{IDSYM}*
SUBPROG (subroutine|function)
B [ \t]
BS [ \t]*
BS_ [ \t]+
COMMA {BS},{BS}
ARGS {BS}("("[^)]*")"){BS}
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{B}PRECISION|{CHAR})
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|RECURSIVE|PURE|ELEMENTAL)
ACCESS_SPEC (PRIVATE|PUBLIC)
/* Assume that attribute statements are almost the same as attributes. */
ATTR_STMT {ATTR_SPEC}|DIMENSION
COMMANDS (BLOCK{BS}DATA|DO|SELECT|CASE|WHERE|IF|THEN|ELSE|MODULE{BS_}PROCEDURE|CONTAINS|IMPLICIT{BS}NONE|CONTAINS|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|DEALLOCATE|SIZE|END{BS}IF|END{BS}DO|WHILE|INQUIRE|OPEN|CLOSE|DATA)
IGNORE (CALL)
/* | */
%option noyywrap
%option stack
%option caseless
/*%option debug*/
%x Start
%x SubCall
%x FuncDef
%x ClassName
%x ClassVar
%x Subprog
%x DocBlock
%x Use
%x UseOnly
%x TypeDecl
%x Declaration
%x DeclContLine
%x Parameterlist
%x String
%%
/*==================================================================*/
/*-------- ignore ------------------------------------------------------------*/
<Start>{IGNORE}/{BS}"("? { // do not search keywords, intrinsics... TODO: complete list
codifyLines(yytext);
}
/*-------- inner construct ---------------------------------------------------*/
<Start>{COMMANDS}/[,( \t\n].* { // hightlight rest of fortran statements
/* font class is defined e.g. in doxygen.css */
startFontClass("keyword");
codifyLines(yytext);
endFontClass();
}
<Start>"end"({BS_}{COMMANDS})?/[ \t\n] {
startFontClass("keyword");
codifyLines(yytext);
endFontClass();
}
/*-------- use statement -------------------------------------------*/
<Start>"use"{BS_} {
codifyLines(yytext);
yy_push_state(YY_START);
BEGIN(Use);
}
<Use>{ID} {
startFontClass("keywordflow");
codifyLines(yytext);
endFontClass();
/* append module name to use dict */
useEntry = new UseEntry();
useEntry->module = yytext;
useMembers->append(yytext, useEntry);
addUse(yytext);
}
<Use>,{BS}"ONLY" { // TODO: rename
codifyLines(yytext);
yy_push_state(YY_START);
BEGIN(UseOnly);
}
<UseOnly>{BS},{BS} { codifyLines(yytext); }
<UseOnly>{ID} {
codifyLines(yytext);
useEntry->onlyNames.append(yytext);
}
<Use,UseOnly>"\n" {
unput(*yytext);
yy_pop_state();
}
/*-------- fortran module -----------------------------------------*/
<Start>("program"|"module"|"type"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { //
startScope();
startFontClass("keyword");
codifyLines(yytext);
endFontClass();
yy_push_state(YY_START);
BEGIN(ClassName);
if (!stricmp(yytext,"module")) currentModule="module";
}
<ClassName>{ID} {
if (currentModule == "module") currentModule=yytext;
generateLink(*g_code,yytext);
yy_pop_state();
}
<ClassName>\n { // interface may be without name
yy_pop_state();
REJECT;
}
<Start>"end"({BS_}"module").* { // just reset currentModule, rest is done in following rule
currentModule=0;
REJECT;
}
<Start>^{BS}"end"({BS}("program"|"module"|"type"|"interface")({BS_}{ID})?)?{BS}/(\n|!) { //
endScope();
startFontClass("keyword");
codifyLines(yytext);
endFontClass();
}
/*-------- subprog definition -------------------------------------*/
<Start>{TYPE_SPEC}{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result
startFontClass("keyword");
codifyLines(yytext);
endFontClass();
}
<Start>{SUBPROG}{BS_} { // Fortran subroutine or function found
startFontClass("keyword");
codifyLines(yytext);
endFontClass();
yy_push_state(YY_START);
BEGIN(Subprog);
}
<Subprog>{ID} { // subroutine/function name
// fprintf(stderr, "===> start subprogram %s\n", yytext);
startScope();
generateLink(*g_code,yytext);
}
<Subprog>"(".* { // ignore rest of line
codifyLines(yytext);
}
<Subprog>"\n" { codifyLines(yytext);
yy_pop_state();
}
<Start>^{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) { // Fortran subroutine or function ends
//cout << "===> end function " << yytext << endl;
endScope();
startFontClass("keyword");
codifyLines(yytext);
endFontClass();
}
/*-------- variable declaration ----------------------------------*/
<Start>"TYPE"{BS}"(" {
yy_push_state(YY_START);
BEGIN(TypeDecl);
startFontClass("keywordtype");
g_code->codify(yytext);
endFontClass();
}
<TypeDecl>{ID} { // link type
g_insideBody=TRUE;
generateLink(*g_code,yytext);
g_insideBody=FALSE;
}
<TypeDecl>")" {
BEGIN(Declaration);
startFontClass("keywordtype");
g_code->codify(yytext);
endFontClass();
}
<Start>{TYPE_SPEC}/[,:( ] {
yy_push_state(YY_START);
BEGIN(Declaration);
startFontClass("keywordtype");
g_code->codify(yytext);
endFontClass();
}
<Start>{ATTR_SPEC} {
startFontClass("keywordtype");
g_code->codify(yytext);
endFontClass();
}
<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable deklaration
startFontClass("keywordtype");
g_code->codify(yytext);
endFontClass();
}
<Declaration>{ID} { // local var
g_code->codify(yytext);
if (g_currentMemberDef && g_currentMemberDef->isFunction())
addLocalVar(yytext);
}
<Declaration>[(] { // start of array specification
bracketCount++;
g_code->codify(yytext);
}
<Declaration>[)] { // end array specification
bracketCount--;
g_code->codify(yytext);
}
<Declaration>"&" { // continuation line
yy_push_state(YY_START);
BEGIN(DeclContLine);
}
<DeclContLine>"\n" { // declaration not yet finished
codifyLines(yytext);
bracketCount = 0;
yy_pop_state();
}
<Declaration>"\n" { // end declaration line
codifyLines(yytext);
bracketCount = 0;
yy_pop_state();
}
/*-------- subprog calls -----------------------------------------*/
<Start>"call"{BS_} {
codifyLines(yytext);
yy_push_state(YY_START);
BEGIN(SubCall);
}
<SubCall>{ID} { // subroutine call
g_insideBody=TRUE;
generateLink(*g_code, yytext);
g_insideBody=FALSE;
yy_pop_state();
}
<Start>{ID}{BS}/"(" { // function call
g_insideBody=TRUE;
generateLink(*g_code, yytext);
g_insideBody=FALSE;
}
/*-------- comments ---------------------------------------------------*/
<Start>\n?{BS}"!>" { // start comment line or comment block
yy_push_state(YY_START);
BEGIN(DocBlock);
docBlock=yytext;
}
<DocBlock>.* { // contents of current comment line
docBlock+=yytext;
}
<DocBlock>"\n"{BS}("!>"|"!"+) { //| comment block (next line is also comment line)
docBlock+=yytext;
}
<DocBlock>"\n" { // comment block ends at the end of this line
docBlock+=yytext;
// remove special comment (default config)
if (Config_getBool("STRIP_CODE_COMMENTS"))
{
g_yyLineNr+=((QCString)docBlock).contains('\n');
endCodeLine();
if (g_yyLineNr<g_inputLines)
{
startCodeLine();
}
}
else // do not remove comment
{
startFontClass("comment");
codifyLines(docBlock);
endFontClass();
}
yy_pop_state();
}
<*>"!"[^>\n].*|"!"$ { // normal comment
if(YY_START == String) REJECT; // ignore in strings
startFontClass("comment");
codifyLines(yytext);
endFontClass();
}
<*>^[Cc*].* { // normal comment
if(! g_isFixedForm) REJECT;
startFontClass("comment");
codifyLines(yytext);
endFontClass();
}
/*------ preprocessor --------------------------------------------*/
<Start>"#".*\n { startFontClass("preprocessor");
codifyLines(yytext);
endFontClass();
}
/*------ variable references? -------------------------------------*/
<Start>"%"{BS}{ID} { // ignore references to elements
g_code->codify(yytext);
}
<Start>{ID} {
g_insideBody=TRUE;
generateLink(*g_code, yytext);
g_insideBody=FALSE;
}
/*------ strings --------------------------------------------------*/
<*>"\\\\" { str+=yytext; /* ignore \\ */}
<*>"\\\""|\\\' { str+=yytext; /* ignore \" */}
<String>\"|\' { // string ends with next quote without previous backspace
if(yytext[0]!=stringStartSymbol) REJECT; // single vs double quote
str+=yytext;
startFontClass("stringliteral");
codifyLines(str);
endFontClass();
yy_pop_state();
}
<String>. {str+=yytext;}
<*>\"|\' { /* string starts */
/* if(YY_START == StrIgnore) REJECT; // ignore in simple comments */
yy_push_state(YY_START);
stringStartSymbol=yytext[0]; // single or double quote
BEGIN(String);
str=yytext;
}
/*-----------------------------------------------------------------------------*/
<*>\n {
codifyLines(yytext);
}
<*>. {
g_code->codify(yytext);
}
%%
/*@ ----------------------------------------------------------------------------
*/
/*===================================================================*/
void resetFortranCodeParserState() {}
void parseFortranCode(CodeOutputInterface &od,const char *className,const QCString &s,
bool exBlock, const char *exName,FileDef *fd,
int startLine,int endLine,bool inlineFragment,
MemberDef *memberDef)
{
//printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
// used parameters
(void)memberDef;
(void)className;
if (s.isEmpty()) return;
g_code = &od;
g_inputString = s;
g_inputPosition = 0;
g_isFixedForm = recognizeFixedForm((const char*)s);
g_currentFontClass = 0;
g_needsTermination = FALSE;
if (endLine!=-1)
g_inputLines = endLine+1;
else
g_inputLines = countLines();
if (startLine!=-1)
g_yyLineNr = startLine;
else
g_yyLineNr = 1;
g_exampleBlock = exBlock;
g_exampleName = exName;
g_sourceFileDef = fd;
if (exBlock && fd==0)
{
// create a dummy filedef for the example
g_sourceFileDef = new FileDef("",exName);
}
if (g_sourceFileDef)
{
setCurrentDoc(g_sourceFileDef->name(),g_sourceFileDef->getSourceFileBase());
}
g_currentDefinition = 0;
g_currentMemberDef = 0;
if (!g_exampleName.isEmpty())
{
g_exampleFile = convertNameToFile(g_exampleName+"-example");
}
g_includeCodeFragment = inlineFragment;
startCodeLine();
g_parmName.resize(0);
g_parmType.resize(0);
fcodeYYrestart( fcodeYYin );
BEGIN( Start );
fcodeYYlex();
if (g_needsTermination)
{
endFontClass();
g_code->endCodeLine();
}
if (exBlock && g_sourceFileDef)
{
// delete the temporary file definition used for this example
delete g_sourceFileDef;
g_sourceFileDef=0;
}
return;
}
#if !defined(YY_FLEX_SUBMINOR_VERSION)
extern "C" { // some bogus code to keep the compiler happy
void fcodeYYdummy() { yy_flex_realloc(0,0); }
}
#elif YY_FLEX_SUBMINOR_VERSION<33
#error "You seem to be using a version of flex newer than 2.5.4 but older than 2.5.33. These versions do NOT work with doxygen! Please use version <=2.5.4 or >=2.5.33 or expect things to be parsed wrongly!"
#else
extern "C" { // some bogus code to keep the compiler happy
void fcodeYYdummy() { yy_top_state(); }
}
#endif