Commit cf0e414d authored by dimitri's avatar dimitri

Release-1.4.3-20050615

parent ad65c6e2
......@@ -92,7 +92,9 @@ EXCLUDE = src/code.cpp \
src/searchindex.cpp \
src/searchindex.h \
src/commentcnv.cpp \
src/commentscan.cpp
src/commentscan.cpp \
src/pycode.cpp \
src/pyscanner.cpp
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
......
DOXYGEN Version 1.4.3-20050530
DOXYGEN Version 1.4.3-20050615
Please read the installation section of the manual
(http://www.doxygen.org/install.html) for instructions.
--------
Dimitri van Heesch (30 May 2005)
Dimitri van Heesch (15 June 2005)
DOXYGEN Version 1.4.3_20050530
DOXYGEN Version 1.4.3_20050615
Please read INSTALL for compilation instructions.
......@@ -17,4 +17,4 @@ to subscribe to the lists or to visit the archives.
Enjoy,
Dimitri van Heesch (dimitri@stack.nl) (30 May 2005)
Dimitri van Heesch (dimitri@stack.nl) (15 June 2005)
1.4.3-20050530
1.4.3-20050615
......@@ -36,7 +36,7 @@ INPUT = index.doc install.doc starting.doc docblocks.doc lists.doc \
autolink.doc output.doc external.doc faq.doc trouble.doc history.doc features.doc \
doxygen_usage.doc doxytag_usage.doc \
doxywizard_usage.doc installdox_usage.doc \
config.doc commands.doc htmlcmds.doc language.doc \
config.doc commands.doc htmlcmds.doc xmlcmds.doc language.doc \
perlmod.doc perlmod_tree.doc arch.doc
FILE_PATTERNS = *.cpp *.h *.doc
EXAMPLE_PATH = ../examples
......
.TH DOXYGEN "1" "DATE" "doxygen VERSION" "User Commands"
.SH NAME
doxygen \- manual page for doxygen VERSION
doxygen \- documentation system for various programming languages
.SH DESCRIPTION
Doxygen version VERSION
Copyright Dimitri van Heesch 1997-2005
Doxygen is a documentation system for C++, C, Java, Objective-C, IDL
(Corba and Microsoft flavors) and to some extent PHP, C#, and D.
.PP
You can use doxygen in a number of ways:
.TP
......@@ -40,5 +40,7 @@ doxygen \fB\-e\fR rtf extensionsFile
.PP
If \fB\-s\fR is specified the comments in the config file will be omitted.
If configName is omitted `Doxyfile' will be used as a default.
.SH AUTHOR
Doxygen version VERSION, Copyright Dimitri van Heesch 1997-2005
.SH SEE ALSO
doxytag(1), doxywizard(1).
......@@ -22,11 +22,11 @@
Plain text will do, but for more fancy or structured output HTML tags
and/or some of doxygen's special commands can be used.
<li>Supports C/C++, Java, (Corba and Microsoft) Java,
IDL, and to some extent C# and PHP sources.
IDL, C#, Objective-C and to some extent D and PHP sources.
<li>Supports documentation of files, namespaces, classes, structs, unions,
templates, variables, functions, typedefs, enums and defines.
<li>JavaDoc (1.1), Qt-Doc, and KDOC compatible.
<li>Automatically generates class diagrams in HTML (as clickable
<li>JavaDoc (1.1), Qt-Doc, and ECMA-334 (C# spec.) compatible.
<li>Automatically generates class and collaboration diagrams in HTML (as clickable
image maps) and \f$\mbox{\LaTeX}\f$ (as Encapsulated PostScript images).
<li>Uses the dot tool of the Graphviz tool kit to generate
include dependency graphs, collaboration diagrams, and
......@@ -76,8 +76,9 @@
<li>Can cope with large projects easily.
</UL>
Although doxygen can be used in any C or C++ project, it was specifically
designed to be used for projects that make use of Troll Tech's
Although doxygen can be used in any C or C++ project,
initially it was specifically designed to be used for projects that make
use of Troll Tech's
<A HREF="http://www.trolltech.com/products/qt.html">Qt toolkit</A>. I have tried to make doxygen
`Qt-compatible'. That is: Doxygen can read the documentation contained in
the Qt source code and create a class browser that looks very similar to the
......
......@@ -17,9 +17,10 @@
/*! \page htmlcmds HTML Commands
Here is a list of all HTML commands that may be used inside the
documentation. Note that all attributes of a HTML tag are passed on to
the HTML output only (the HREF and NAME attributes for the A tag are the
only exception).
documentation. Note that although these HTML tags are translated to the
proper commands for outer formats other than HTML, all attributes
of a HTML tag are passed on to the HTML output only
(the HREF and NAME attributes for the A tag are the only exception).
<ul>
<li><tt>\<A HREF="..."\></tt> Starts a HTML hyper-link (HTML only).
......
......@@ -97,6 +97,8 @@ The second part forms a reference manual:
used within the documentation.
<li>Section \ref htmlcmds shows an overview of the HTML commands that
can be used within the documentation.
<li>Section \ref xmlcmds shows an overview of the XML commands that
can be used within the documentation.
</ul>
The third part provides information for developers:
......@@ -186,6 +188,7 @@ Thanks go to:
<li>Tim Mensch for adding the todo command.
<li>Christian Hammond for redesigning the web-site.
<li>Ken Wong for providing the HTML tree view code.
<li>Talin for adding support for C# style comments with XML markup.
<li>Petr Prikryl for coordinating the internationalisation support.
All language maintainers for providing translations into many languages.
<li>Gerald Steffens of <a href="http://www.e-trend.de">E-trend</a>
......
/******************************************************************************
*
*
*
* Copyright (C) 1997-2005 by 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.
*
*/
/*! \page xmlcmds XML Commands
Doxygen supports most of the XML commands that are typically used in C#
code comments. The XML tags are defined in Appendix E of the
<a href="http://www.ecma-international.org/publications/standards/Ecma-334.htm">ECMA-334</a>
standard, which defines the C# language. Unfortunately, the specification is
not very precise and a number of the examples given are of poor quality.
Here is the list of tags supported by doxygen:
<ul>
<li><tt>\<c\></tt> Identifies inline text that should be rendered as a
piece of code. Similar to using <tt>\<tt\></tt>text<tt>\</tt\></tt>.
<li><tt>\<code\></tt> Set one or more lines of source code or program output.
Note that this command behaves like <tt>\\code ... \\endcode</tt>
for C# code, but it behaves like the HTML equivalent
<tt>\<code\>...\</code\></tt> for other languages.
<li><tt>\<description\></tt> Part of a <tt>\<list\></tt> command, describes an item.
<li><tt>\<example\></tt> Marks a block of text as an example, ignored by doxygen.
<li><tt>\<exception cref="member"\></tt> Identifies the exception a
method can throw.
<li><tt>\<include\></tt> Can be used to import a piece of XML from an external
file. Ignored by doxygen at the moment.
<li><tt>\<item\></tt> List item. Can only be used inside a <tt>\<list\></tt> context.
<li><tt>\<list type="type"\></tt> Starts a list, supported types are <tt>bullet</tt>
or <tt>number</tt>. A list consists of a number of <tt>\<item\></tt> tags.
<li><tt>\<para\></tt> Identifies a paragraph of text.
<li><tt>\<param name="paramName"\></tt> Marks a piece of text as the documentation
for parameter "paramName". Similar to
using \ref cmdparam "\\param".
<li><tt>\<paramref name="paramName"\></tt> Refers to a parameter with name
"paramName". Similar to using \ref cmda "\\a".
<li><tt>\<permission\></tt> Identifies the security accessibility of a member.
Ignored by doygen.
<li><tt>\<remarks\></tt> Identifies the detailed description.
<li><tt>\<returns\></tt> Marks a piece of text as the return value of a
function or method. Similar to using \ref cmdreturn "\\return".
<li><tt>\<see cref="member"\></tt> Refers to a member. Similar to \ref cmdref "\\ref".
<li><tt>\<seealso cref="member"\></tt> Starts a "See also" section referring
to "member". Similar to using \ref cmdsa "\\sa" member.
<li><tt>\<summary\></tt> Identifies the brief description.
Similar to using \ref cmdbrief "\\brief".
<li><tt>\<value\></tt> Identifies a property. Ignored by doxygen.
</ul>
Here is an example of a typical piece of code using some of the above commands:
\code
/// <summary>
/// A search engine.
/// </summary>
class Engine
{
/// <summary>
/// The Search method takes a series of parameters to specify the search criterion
/// and returns a dataset containing the result set.
/// </summary>
/// <param name="connectionString">the connection string to connect to the
/// database holding the content to search</param>
/// <param name="maxRows">The maximum number of rows to
/// return in the result set</param>
/// <param name="searchString">The text that we are searching for</param>
/// <returns>A DataSet instance containing the matching rows. It contains a maximum
/// number of rows specified by the maxRows parameter</returns>
public DataSet Search(string connectionString, int maxRows, int searchString)
{
DataSet ds = new DataSet();
return ds;
}
}
\endcode
*/
......@@ -47,6 +47,7 @@ clean: Makefile.libdoxygen Makefile.libdoxycfg Makefile.doxygen Makefile.doxytag
distclean: clean
-$(RM) scanner.cpp code.cpp config.cpp pre.cpp ce_lex.cpp \
ce_parse.cpp ce_parse.h doxytag.cpp tag.cpp commentscan.cpp \
declinfo.cpp defargs.cpp commentcnv.cpp doctokenizer.cpp
declinfo.cpp defargs.cpp commentcnv.cpp doctokenizer.cpp \
pycode.cpp pyscanner.cpp
FORCE:
......@@ -100,7 +100,6 @@ CommandMap cmdMap[] =
{ "$", CMD_DOLLAR },
{ "#", CMD_HASH },
{ "%", CMD_PERCENT },
//{ "~", CMD_LANGSWITCH },
{ "_internalref", CMD_INTERNALREF },
{ "dot", CMD_DOT },
{ "enddot", CMD_ENDDOT },
......@@ -112,42 +111,6 @@ CommandMap cmdMap[] =
//----------------------------------------------------------------------------
int CmdMapper::map(const char *name)
{
return instance()->find(name);
}
void CmdMapper::freeInstance()
{
delete m_instance; m_instance=0;
}
CmdMapper *CmdMapper::instance()
{
if (m_instance==0) m_instance = new CmdMapper;
return m_instance;
}
CmdMapper::CmdMapper() : m_map(89)
{
m_map.setAutoDelete(TRUE);
CommandMap *p = cmdMap;
while (p->cmdName)
{
m_map.insert(p->cmdName,new int(p->cmdId));
p++;
}
}
int CmdMapper::find(const char *name)
{
int *result = m_map.find(name);
if (result) return *result; else return CMD_UNKNOWN;
}
CmdMapper *CmdMapper::m_instance=0;
//----------------------------------------------------------------------------
CommandMap htmlTagMap[] =
{
{ "strong", HTML_BOLD },
......@@ -188,43 +151,37 @@ CommandMap htmlTagMap[] =
{ "h6", HTML_H6 },
{ "span", HTML_SPAN },
{ "div", HTML_DIV },
{ "c", XML_C },
// { "code", XML_CODE }, <= ambigious <code> is also a HTML tag
{ "description",XML_DESCRIPTION },
{ "example", XML_EXAMPLE },
{ "exception", XML_EXCEPTION },
{ "include", XML_INCLUDE },
{ "item", XML_ITEM },
{ "list", XML_LIST },
{ "para", XML_PARA },
{ "param", XML_PARAM },
{ "paramref", XML_PARAMREF },
{ "permission", XML_PERMISSION },
{ "remarks", XML_REMARKS },
{ "returns", XML_RETURNS },
{ "see", XML_SEE },
{ "seealso", XML_SEEALSO },
{ "summary", XML_SUMMARY },
{ "value", XML_VALUE },
{ 0, 0 }
};
//----------------------------------------------------------------------------
int HtmlTagMapper::map(const char *name)
{
return instance()->find(name);
}
void HtmlTagMapper::freeInstance()
{
delete m_instance; m_instance=0;
}
HtmlTagMapper *HtmlTagMapper::instance()
{
if (m_instance==0) m_instance = new HtmlTagMapper;
return m_instance;
}
Mapper *Mappers::cmdMapper = new Mapper(cmdMap);
Mapper *Mappers::htmlTagMapper = new Mapper(htmlTagMap);
HtmlTagMapper::HtmlTagMapper() : m_map(89)
void Mappers::freeMappers()
{
m_map.setAutoDelete(TRUE);
CommandMap *p = htmlTagMap;
while (p->cmdName)
{
m_map.insert(p->cmdName,new int(p->cmdId));
p++;
}
}
int HtmlTagMapper::find(const char *name)
{
int *result = m_map.find(name);
if (result) return *result; else return HTML_UNKNOWN;
delete cmdMapper; cmdMapper = 0;
delete htmlTagMapper; htmlTagMapper = 0;
}
HtmlTagMapper *HtmlTagMapper::m_instance=0;
//----------------------------------------------------------------------------
......@@ -111,67 +111,92 @@ enum CommandType
enum HtmlTagType
{
HTML_UNKNOWN = 0,
HTML_CENTER = 1,
HTML_TABLE = 2,
HTML_CAPTION = 3,
HTML_SMALL = 4,
HTML_CODE = 5,
HTML_IMG = 6,
HTML_PRE = 7,
HTML_SUB = 8,
HTML_SUP = 9,
HTML_TR = 10,
HTML_TD = 11,
HTML_TH = 12,
HTML_OL = 13,
HTML_UL = 14,
HTML_LI = 15,
HTML_EMPHASIS = 16,
HTML_HR = 17,
HTML_DL = 18,
HTML_DT = 19,
HTML_DD = 20,
HTML_BR = 21,
HTML_A = 22,
HTML_BOLD = 23,
HTML_P = 24,
HTML_H1 = 25,
HTML_H2 = 26,
HTML_H3 = 27,
HTML_H4 = 28,
HTML_H5 = 29,
HTML_H6 = 30,
HTML_SPAN = 31,
HTML_DIV = 32
HTML_UNKNOWN = 0,
HTML_CENTER = 1,
HTML_TABLE = 2,
HTML_CAPTION = 3,
HTML_SMALL = 4,
HTML_CODE = 5,
HTML_IMG = 6,
HTML_PRE = 7,
HTML_SUB = 8,
HTML_SUP = 9,
HTML_TR = 10,
HTML_TD = 11,
HTML_TH = 12,
HTML_OL = 13,
HTML_UL = 14,
HTML_LI = 15,
HTML_EMPHASIS = 16,
HTML_HR = 17,
HTML_DL = 18,
HTML_DT = 19,
HTML_DD = 20,
HTML_BR = 21,
HTML_A = 22,
HTML_BOLD = 23,
HTML_P = 24,
HTML_H1 = 25,
HTML_H2 = 26,
HTML_H3 = 27,
HTML_H4 = 28,
HTML_H5 = 29,
HTML_H6 = 30,
HTML_SPAN = 31,
HTML_DIV = 32,
XML_CmdMask = 0x100,
XML_C = XML_CmdMask + 0,
XML_CODE = XML_CmdMask + 1,
XML_DESCRIPTION= XML_CmdMask + 2,
XML_EXAMPLE = XML_CmdMask + 3,
XML_EXCEPTION = XML_CmdMask + 4,
XML_INCLUDE = XML_CmdMask + 5,
XML_ITEM = XML_CmdMask + 6,
XML_LIST = XML_CmdMask + 7,
XML_PARA = XML_CmdMask + 8,
XML_PARAM = XML_CmdMask + 9,
XML_PARAMREF = XML_CmdMask + 10,
XML_PERMISSION = XML_CmdMask + 11,
XML_REMARKS = XML_CmdMask + 12,
XML_RETURNS = XML_CmdMask + 13,
XML_SEE = XML_CmdMask + 14,
XML_SEEALSO = XML_CmdMask + 15,
XML_SUMMARY = XML_CmdMask + 16,
XML_VALUE = XML_CmdMask + 17
};
class CmdMapper
class Mapper
{
public:
static int map(const char *name);
static void freeInstance();
int map(const char *n)
{
QCString name=n;
int *result;
return !name.isEmpty() && (result=m_map.find(name.lower())) ? *result: 0;
}
Mapper(const CommandMap *cm) : m_map(89)
{
m_map.setAutoDelete(TRUE);
const CommandMap *p = cm;
while (p->cmdName)
{
m_map.insert(p->cmdName,new int(p->cmdId));
p++;
}
}
private:
static CmdMapper *instance();
CmdMapper();
int find(const char *name);
QDict<int> m_map;
static CmdMapper *m_instance;
};
class HtmlTagMapper
struct Mappers
{
public:
static int map(const char *name);
static void freeInstance();
private:
static HtmlTagMapper *instance();
HtmlTagMapper();
int find(const char *name);
QDict<int> m_map;
static HtmlTagMapper *m_instance;
static void freeMappers();
static Mapper *cmdMapper;
static Mapper *htmlTagMapper;
};
......
......@@ -21,13 +21,14 @@
#include "qtbc.h"
#include <stdio.h>
class BaseCodeDocInterface;
class CodeOutputInterface;
class FileDef;
class MemberDef;
extern void parseCode(BaseCodeDocInterface &,const char *,const QCString &,
extern void parseCCode(CodeOutputInterface &,const char *,const QCString &,
bool ,const char *,FileDef *fd=0,
int startLine=-1,int endLine=-1,bool inlineFragment=FALSE);
extern void initParseCodeContext();
extern void setParameterList(MemberDef *md);
int startLine=-1,int endLine=-1,bool inlineFragment=FALSE,
MemberDef *memberDef=0);
extern void resetCCodeParserState();
#endif
......@@ -27,7 +27,6 @@
#include <qdir.h>
#include "qtbc.h"
#include "scanner.h"
#include "entry.h"
#include "doxygen.h"
#include "message.h"
......@@ -50,7 +49,7 @@
* statics
*/
static BaseCodeDocInterface * g_code;
static CodeOutputInterface * g_code;
static ClassSDict g_codeClassSDict(17);
static QCString g_curClassName;
......@@ -346,11 +345,8 @@ class CallContext
void clear()
{
DBG_CTX((stderr,"** Clear call context\n"));
Ctx *ctx = m_classList.getLast();
if (ctx)
{
ctx->cd=0;
}
m_classList.clear();
m_classList.append(new Ctx);
}
ClassDef *getClass() const
{
......@@ -549,7 +545,7 @@ static void codifyLines(char *text)
* 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(BaseCodeDocInterface &ol,
static void writeMultiLineCodeLink(CodeOutputInterface &ol,
const char *ref,const char *file,
const char *anchor,const char *text)
{
......@@ -600,7 +596,7 @@ static void addParmType()
g_parmName.resize(0) ;
}
void setParameterList(MemberDef *md)
static void setParameterList(MemberDef *md)
{
g_classScope = md->getClassDef() ? md->getClassDef()->name().data() : "";
ArgumentList *al = md->argumentList();
......@@ -614,7 +610,7 @@ void setParameterList(MemberDef *md)
if (i!=-1) g_parmType = g_parmType.left(i);
i = g_parmType.find('&');
if (i!=-1) g_parmType = g_parmType.left(i);
if (g_parmType.left(6)=="const ") g_parmType = g_parmType.right(g_parmType.length()-6);
g_parmType.stripPrefix("const ");
g_parmType=g_parmType.stripWhiteSpace();
g_theVarContext.addVariable(g_parmType,g_parmName);
a = al->next();
......@@ -767,7 +763,7 @@ static void addDocCrossReference(MemberDef *src,MemberDef *dst)
static bool getLinkInScope(const QCString &c, // scope
const QCString &m, // member
const char *memberText, // exact text
BaseCodeDocInterface &ol,
CodeOutputInterface &ol,
const char *text
)
{
......@@ -825,7 +821,7 @@ static bool getLinkInScope(const QCString &c, // scope
static bool getLink(const char *className,
const char *memberName,
BaseCodeDocInterface &ol,
CodeOutputInterface &ol,
const char *text=0)
{
QCString m=removeRedundantWhiteSpace(memberName);
......@@ -843,7 +839,7 @@ static bool getLink(const char *className,
return TRUE;
}
static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName,
static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName,
bool typeOnly=FALSE)
{
int i=0;
......@@ -963,7 +959,7 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName,
}
}
static bool generateClassMemberLink(BaseCodeDocInterface &ol,ClassDef *mcd,const char *memName)
static bool generateClassMemberLink(CodeOutputInterface &ol,ClassDef *mcd,const char *memName)
{
if (mcd)
{
......@@ -1025,7 +1021,7 @@ static bool generateClassMemberLink(BaseCodeDocInterface &ol,ClassDef *mcd,const
return FALSE;
}
static void generateMemberLink(BaseCodeDocInterface &ol,const QCString &varName,
static void generateMemberLink(CodeOutputInterface &ol,const QCString &varName,
char *memName)
{
//printf("generateMemberLink(object=%s,mem=%s) classScope=%s\n",
......@@ -1120,7 +1116,7 @@ static void generateMemberLink(BaseCodeDocInterface &ol,const QCString &varName,
return;
}
static void generateFunctionLink(BaseCodeDocInterface &ol,char *funcName)
static void generateFunctionLink(CodeOutputInterface &ol,char *funcName)
{
//CodeClassDef *ccd=0;
ClassDef *ccd=0;
......@@ -2412,7 +2408,7 @@ OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
g_code->codify(yytext);
endFontClass();
}
<MemberCall2,FuncCall>[a-z_A-Z][:a-z_A-Z0-9]*({B}*"<"[^\n\<\>]*">")? {
<MemberCall2,FuncCall>[a-z_A-Z][:a-z_A-Z0-9]*({B}*"<"[^\n\[\](){}<>]*">")? {
addParmType();
g_parmName=yytext;
generateClassOrGlobalLink(*g_code,yytext,!g_insideBody);
......@@ -2812,7 +2808,7 @@ OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
}
}
<*>"//"[!/][^\n]*\n { // strip special one-line comment
if (YY_START==SkipComment) REJECT;
if (YY_START==SkipComment || YY_START==SkipString) REJECT;
if (Config_getBool("STRIP_CODE_COMMENTS"))
{
char c[2]; c[0]='\n'; c[1]=0;
......@@ -2863,6 +2859,7 @@ OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
}
}
<*>"/*"[!*]/[^/*] { // special C comment block half way a line
if (YY_START==SkipString) REJECT;
if (Config_getBool("STRIP_CODE_COMMENTS"))
{
g_lastSpecialCContext = YY_START;
......@@ -2880,7 +2877,9 @@ OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
BEGIN(SkipComment);
}
}
<*>"/*"("!"?)"*/" { if (!Config_getBool("STRIP_CODE_COMMENTS"))
<*>"/*"("!"?)"*/" {
if (YY_START==SkipString) REJECT;
if (!Config_getBool("STRIP_CODE_COMMENTS"))
{
startFontClass("comment");
g_code->codify(yytext);
......@@ -2984,7 +2983,7 @@ static void restoreObjCContext()
}
}
void initParseCodeContext()
void resetCCodeParserState()
{
//printf("***initParseCodeContext()\n");
g_theVarContext.clear();
......@@ -2994,9 +2993,10 @@ void initParseCodeContext()
g_anchorCount = 0;
}
void parseCode(BaseCodeDocInterface &od,const char *className,const QCString &s,
void parseCCode(CodeOutputInterface &od,const char *className,const QCString &s,
bool exBlock, const char *exName,FileDef *fd,
int startLine,int endLine,bool inlineFragment)
int startLine,int endLine,bool inlineFragment,
MemberDef *memberDef)
{
//printf("***parseCode()\n");
if (s.isEmpty()) return;
......@@ -3048,6 +3048,7 @@ void parseCode(BaseCodeDocInterface &od,const char *className,const QCString &s,
g_args.resize(0);
g_parmName.resize(0);
g_parmType.resize(0);
if (memberDef) setParameterList(memberDef);
codeYYrestart( codeYYin );
BEGIN( Body );
codeYYlex();
......
......@@ -454,9 +454,16 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
<CondLine>[ \t]*
<CComment,ReadLine>[\\@]"cond"[ \t]*\n |
<CondLine>. { // forgot section id?
bool oldSkip=g_skip;
startCondSection(" "); // fake section id causing the section to be hidden unconditionally
if (g_condCtx==CComment && !oldSkip && g_skip)
{
//printf("** Adding terminator for comment!\n");
ADDCHAR('*');
ADDCHAR('/');
}
if (*yytext=='\n') g_lineNr++;
if (YY_START==CondLine) BEGIN(g_condCtx);
BEGIN(g_condCtx);
}
<CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias
QCString *pValue=Doxygen::aliasDict[yytext+1];
......
......@@ -42,7 +42,6 @@
#include "outputlist.h"
#include "membergroup.h"
#include "reflist.h"
#include "code.h"
#include "debug.h"
#include "parserintf.h"
......@@ -715,6 +714,7 @@ ID "$"?[a-z_A-Z][a-z_A-Z0-9]*
LABELID [a-z_A-Z][a-z_A-Z0-9\-]*
SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?)
SCOPENAME "$"?(({ID}?{BN}*"::"{BN}*)*)((~{BN}*)?{ID})
MAILADR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
%option noyywrap
......@@ -770,6 +770,9 @@ SCOPENAME "$"?(({ID}?{BN}*"::"{BN}*)*)((~{BN}*)?{ID})
* words and whitespace and other characters (#,?!, etc).
* grouping commands (e.g. @{ and @})
* language switch (e.g. \~english or \~).
* mail adress (e.g. dimitri@stack.nl).
* quoted text, such as "foo@bar"
* XML commands, <summary></summary><remarks></remarks>
*/
<Comment>{CMD}{CMD}[a-z_A-Z]+{B}* { // escaped command
......@@ -778,6 +781,12 @@ SCOPENAME "$"?(({ID}?{BN}*"::"{BN}*)*)((~{BN}*)?{ID})
<Comment>{CMD}{CMD}"~"[a-z_A-Z]* { // escaped command
addOutput(yytext);
}
<Comment>{MAILADR} { // mail adress
addOutput(yytext);
}
<Comment>"\""[^"\n]*"\"" { // quoted text
addOutput(yytext);
}
<Comment>("\\"[a-z_A-Z]+)+"\\" { // directory (or chain of commands!)
addOutput(yytext);
}
......@@ -791,6 +800,14 @@ SCOPENAME "$"?(({ID}?{BN}*"::"{BN}*)*)((~{BN}*)?{ID})
// continue with the same input
REJECT;
}
<Comment>"<summary>" { // start of a .NET XML style brief description
setOutput(OutputBrief);
}
<Comment>"<remarks>"|"</summary>" { // start of a .NET XML style detailed description
setOutput(OutputDoc);
}
<Comment>"</remarks>" { // end of a brief or detailed description
}
<Comment>"<!--" {
BEGIN(HtmlComment);
}
......
......@@ -1722,7 +1722,7 @@ void Config::create()
"SHOW_DIRECTORIES",
"If the sources in your project are distributed over multiple directories \n"
"then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy \n"
"in the documentation.\n",
"in the documentation. The default is YES.\n",
TRUE
);
cs = addString( "FILE_VERSION_FILTER",
......
......@@ -28,7 +28,6 @@
#include "defargs.h"
#include "outputgen.h"
#include "dot.h"
#include "code.h"
#include <qdir.h>
#include <qfile.h>
......
......@@ -32,6 +32,7 @@
#include "pagedef.h"
#include "section.h"
#include "htags.h"
#include "parserintf.h"
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define popen _popen
......@@ -81,6 +82,11 @@ Definition::Definition(const char *df,int dl,
{
//QCString ns;
m_defFileName = df;
int lastDot = m_defFileName.findRev('.');
if (lastDot!=-1)
{
m_defFileExt = m_defFileName.mid(lastDot);
}
m_defLine = dl;
m_name=name;
if (m_name!="<globalScope>")
......@@ -459,12 +465,23 @@ void Definition::writeInlineCode(OutputList &ol,const char *scopeName)
actualStart,actualEnd,codeFragment)
)
{
initParseCodeContext();
ParserInterface *pIntf = Doxygen::parserManager->getParser(m_defFileExt);
pIntf->resetCodeParserState();
//printf("Read:\n`%s'\n\n",codeFragment.data());
if (definitionType()==TypeMember) setParameterList((MemberDef *)this);
MemberDef *thisMd = 0;
if (definitionType()==TypeMember) thisMd = (MemberDef *)this;
ol.startCodeFragment();
parseCode(ol,scopeName,codeFragment,FALSE,0,
m_bodyDef,actualStart,actualEnd,TRUE);
pIntf->parseCode(ol, // codeOutIntf
scopeName, // scope
codeFragment, // input
FALSE, // isExample
0, // exampleName
m_bodyDef, // fileDef
actualStart, // startLine
actualEnd, // endLine
TRUE, // inlineFragment
thisMd // memberDef
);
ol.endCodeFragment();
ol.newParagraph();
}
......
......@@ -117,6 +117,9 @@ class Definition
/*! returns the file in which this definition was found */
QCString getDefFileName() const { return m_defFileName; }
/*! returns the file in which this definition was found */
QCString getDefFileExtension() const { return m_defFileExt; }
/*! returns the line number at which the definition was found */
int getDefLine() const { return m_defLine; }
......@@ -207,6 +210,7 @@ class Definition
// where the item was found
QCString m_defFileName;
int m_defLine;
QCString m_defFileExt;
/*! The class, namespace in which this class is located
*/
......
......@@ -688,7 +688,7 @@ static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
g_token->name.data(),cmdName.data());
break;
case TK_HTMLTAG:
if (insideLI(parent) && HtmlTagMapper::map(g_token->name) && g_token->endTag)
if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag)
{ // ignore </li> as the end of a style command
continue;
}
......@@ -969,7 +969,7 @@ reparsetoken:
switch (tok)
{
case TK_COMMAND:
switch (CmdMapper::map(tokenName))
switch (Mappers::cmdMapper->map(tokenName))
{
case CMD_BSLASH:
children.append(new DocSymbol(parent,DocSymbol::BSlash));
......@@ -1124,7 +1124,7 @@ reparsetoken:
break;
case TK_HTMLTAG:
{
switch (HtmlTagMapper::map(tokenName))
switch (Mappers::htmlTagMapper->map(tokenName))
{
case HTML_DIV:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found <div> tag in heading\n");
......@@ -1812,7 +1812,7 @@ void DocSecRefList::parse()
{
if (tok==TK_COMMAND)
{
switch (CmdMapper::map(g_token->name))
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_SECREFITEM:
{
......@@ -2067,7 +2067,7 @@ QString DocLink::parse(bool isJavaLink)
switch (tok)
{
case TK_COMMAND:
switch (CmdMapper::map(g_token->name))
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_ENDLINK:
if (isJavaLink)
......@@ -2314,7 +2314,7 @@ int DocHtmlHeader::parse()
break;
case TK_HTMLTAG:
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_H1 && g_token->endTag) // found </h1> tag
{
if (m_level!=1)
......@@ -2438,7 +2438,7 @@ int DocHRef::parse()
break;
case TK_HTMLTAG:
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_A && g_token->endTag) // found </a> tag
{
goto endhref;
......@@ -2579,7 +2579,7 @@ int DocIndexEntry::parse()
}
break;
case TK_COMMAND:
switch (CmdMapper::map(g_token->name))
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_BSLASH: m_entry+='\\'; break;
case CMD_AT: m_entry+='@'; break;
......@@ -2634,7 +2634,7 @@ int DocHtmlCaption::parse()
break;
case TK_HTMLTAG:
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_CAPTION && g_token->endTag) // found </caption> tag
{
retval = RetVal_OK;
......@@ -2686,7 +2686,7 @@ int DocHtmlCell::parse()
retval=par->parse();
if (retval==TK_HTMLTAG)
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_TD && g_token->endTag) // found </dt> tag
{
retval=TK_NEWPARA; // ignore the tag
......@@ -2725,7 +2725,7 @@ int DocHtmlRow::parse()
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_TD && !g_token->endTag) // found <td> tag
{
}
......@@ -2789,7 +2789,7 @@ getrow:
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_TR && !g_token->endTag) // found <tr> tag
{
// no caption, just rows
......@@ -2888,7 +2888,7 @@ int DocHtmlDescTitle::parse()
{
QString cmdName=g_token->name;
bool isJavaLink=FALSE;
switch (CmdMapper::map(cmdName))
switch (Mappers::cmdMapper->map(cmdName))
{
case CMD_REF:
{
......@@ -2964,7 +2964,7 @@ int DocHtmlDescTitle::parse()
break;
case TK_HTMLTAG:
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_DD && !g_token->endTag) // found <dd> tag
{
retval = RetVal_DescData;
......@@ -3054,7 +3054,7 @@ int DocHtmlDescList::parse()
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_DT && !g_token->endTag) // found <dt> tag
{
// continue
......@@ -3137,6 +3137,40 @@ int DocHtmlListItem::parse()
return retval;
}
int DocHtmlListItem::parseXml()
{
DBG(("DocHtmlListItem::parseXml() start\n"));
int retval=0;
g_nodeStack.push(this);
// parse one or more paragraphs
bool isFirst=TRUE;
DocPara *par=0;
do
{
par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
m_children.append(par);
retval=par->parse();
if (retval==0) break;
//printf("new item: retval=%x g_token->name=%s g_token->endTag=%d\n",
// retval,g_token->name.data(),g_token->endTag);
if (retval==RetVal_ListItem)
{
break;
}
}
while (retval!=RetVal_CloseXml);
if (par) par->markLast();
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
DBG(("DocHtmlListItem::parseXml() end retval=%x\n",retval));
return retval;
}
//---------------------------------------------------------------------------
int DocHtmlList::parse()
......@@ -3153,7 +3187,7 @@ int DocHtmlList::parse()
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=HtmlTagMapper::map(g_token->name);
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_LI && !g_token->endTag) // found <li> tag
{
// ok, we can go on.
......@@ -3198,6 +3232,68 @@ endlist:
return retval==RetVal_EndList ? RetVal_OK : retval;
}
int DocHtmlList::parseXml()
{
DBG(("DocHtmlList::parseXml() start\n"));
int retval=RetVal_OK;
int num=1;
g_nodeStack.push(this);
// get next token
int tok=doctokenizerYYlex();
// skip whitespace and paragraph breaks
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
//printf("g_token->name=%s g_token->endTag=%d\n",g_token->name.data(),g_token->endTag);
if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
{
// ok, we can go on.
}
else // found some other tag
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <item> tag but "
"found <%s> instead!",g_token->name.data());
goto endlist;
}
}
else if (tok==0) // premature end of comment
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
" for a html list item");
goto endlist;
}
else // token other than html token
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <item> tag but found %s token instead!",
tokToString(tok));
goto endlist;
}
do
{
DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
m_children.append(li);
retval=li->parseXml();
if (retval==0) break;
//printf("retval=%x g_token->name=%s\n",retval,g_token->name.data());
} while (retval==RetVal_ListItem);
if (retval==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while inside <list type=\"%s\"> block",
m_type==Unordered ? "bullet" : "number");
}
endlist:
DBG(("DocHtmlList::parseXml() end retval=%x\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval==RetVal_EndList ? RetVal_OK : retval;
}
//---------------------------------------------------------------------------
int DocSimpleListItem::parse()
......@@ -3383,6 +3479,66 @@ int DocSimpleSect::parseRcs()
return RetVal_OK;
}
int DocSimpleSect::parseXml()
{
DBG(("DocSimpleSect::parse() start\n"));
g_nodeStack.push(this);
int retval = RetVal_OK;
for (;;)
{
// add new paragraph as child
DocPara *par = new DocPara(this);
if (m_children.isEmpty())
{
par->markFirst();
}
else
{
ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
((DocPara *)m_children.last())->markLast(FALSE);
}
par->markLast();
m_children.append(par);
// parse the contents of the paragraph
retval = par->parse();
if (retval == 0) break;
if (retval == RetVal_CloseXml)
{
retval = RetVal_OK;
break;
}
}
DBG(("DocSimpleSect::parseXml() end retval=%d\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
void DocSimpleSect::appendLinkWord(const QString &word)
{
DocPara *p;
if (m_children.isEmpty() || m_children.last()->kind()!=DocNode::Kind_Para)
{
p = new DocPara(this);
m_children.append(p);
}
else
{
p = (DocPara *)m_children.last();
// Comma-seperate <seealso> links.
p->injectToken(TK_WORD,",");
p->injectToken(TK_WHITESPACE," ");
}
g_inSeeBlock=TRUE;
p->injectToken(TK_LNKWORD,word);
g_inSeeBlock=FALSE;
}
//--------------------------------------------------------------------------
int DocParamList::parse(const QString &cmdName)
......@@ -3390,6 +3546,7 @@ int DocParamList::parse(const QString &cmdName)
int retval=RetVal_OK;
DBG(("DocParamList::parse() start\n"));
g_nodeStack.push(this);
DocPara *par=0;
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
......@@ -3425,9 +3582,11 @@ int DocParamList::parse(const QString &cmdName)
}
ASSERT(tok==TK_WHITESPACE);
retval = m_paragraph->parse();
m_paragraph->markFirst();
m_paragraph->markLast();
par = new DocPara(this);
m_paragraphs.append(par);
retval = par->parse();
par->markFirst();
par->markLast();
endparamlist:
DBG(("DocParamList::parse() end retval=%d\n",retval));
......@@ -3436,9 +3595,76 @@ endparamlist:
return retval;
}
int DocParamList::parseXml(const QString &paramName)
{
int retval=RetVal_OK;
DBG(("DocParamList::parseXml() start\n"));
g_nodeStack.push(this);
g_token->name = paramName;
if (m_type==DocParamSect::Param)
{
g_hasParamCommand=TRUE;
checkArgumentName(g_token->name,TRUE);
}
else if (m_type==DocParamSect::RetVal)
{
g_hasReturnCommand=TRUE;
checkArgumentName(g_token->name,FALSE);
}
handleLinkedWord(this,m_params);
do
{
DocPara *par = new DocPara(this);
retval = par->parse();
if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
// after </para> and before </param>
{
delete par;
break;
}
else // append the paragraph to the list
{
if (m_paragraphs.isEmpty())
{
par->markFirst();
}
else
{
m_paragraphs.last()->markLast(FALSE);
}
par->markLast();
m_paragraphs.append(par);
}
if (retval == 0) break;
} while (retval==RetVal_CloseXml &&
Mappers::htmlTagMapper->map(g_token->name)!=XML_PARAM &&
Mappers::htmlTagMapper->map(g_token->name)!=XML_EXCEPTION);
if (retval==0) /* premature end of comment block */
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unterminated param or exception tag");
}
else
{
retval=RetVal_OK;
}
DBG(("DocParamList::parse() end retval=%d\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//--------------------------------------------------------------------------
int DocParamSect::parse(const QString &cmdName,Direction d)
int DocParamSect::parse(const QString &cmdName,bool xmlContext, Direction d)
{
int retval=RetVal_OK;
DBG(("DocParamSect::parse() start\n"));
......@@ -3457,7 +3683,14 @@ int DocParamSect::parse(const QString &cmdName,Direction d)
pl->markLast();
}
m_children.append(pl);
retval = pl->parse(cmdName);
if (xmlContext)
{
retval = pl->parseXml(cmdName);
}
else
{
retval = pl->parse(cmdName);
}
DBG(("DocParamSect::parse() end retval=%d\n",retval));
DocNode *n=g_nodeStack.pop();
......@@ -3467,8 +3700,7 @@ int DocParamSect::parse(const QString &cmdName,Direction d)
//--------------------------------------------------------------------------
int DocPara::handleSimpleSection(DocSimpleSect::Type t)
int DocPara::handleSimpleSection(DocSimpleSect::Type t, bool xmlContext)
{
DocSimpleSect *ss=0;
if (!m_children.isEmpty() && // previous element
......@@ -3484,12 +3716,21 @@ int DocPara::handleSimpleSection(DocSimpleSect::Type t)
ss=new DocSimpleSect(this,t);
m_children.append(ss);
}
int rv = ss->parse(t==DocSimpleSect::User);
int rv = RetVal_OK;
if (xmlContext)
{
return ss->parseXml();
}
else
{
rv = ss->parse(t==DocSimpleSect::User);
}
return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
}
int DocPara::handleParamSection(const QString &cmdName,
DocParamSect::Type t,
bool xmlContext=FALSE,
int direction=DocParamSect::Unspecified)
{
DocParamSect *ps=0;
......@@ -3505,7 +3746,7 @@ int DocPara::handleParamSection(const QString &cmdName,
ps=new DocParamSect(this,t);
m_children.append(ps);
}
int rv=ps->parse(cmdName,(DocParamSect::Direction)direction);
int rv=ps->parse(cmdName,xmlContext,(DocParamSect::Direction)direction);
return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
}
......@@ -3777,11 +4018,36 @@ int DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
return (retval==RetVal_OK) ? TK_NEWPARA : retval;
}
// For XML tags whose content is stored in attributes rather than
// contained within the element, we need a way to inject the attribute
// text into the current paragraph.
bool DocPara::injectToken(int tok,const QString &tokText)
{
g_token->name = tokText;
return defaultHandleToken(this,tok,m_children);
}
int DocPara::handleStartCode()
{
int retval = doctokenizerYYlex();
// search for the first non-whitespace line, index is stored in li
int i=0,li=0,l=g_token->verb.length();
while (i<l && g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n')
{
if (g_token->verb.at(i)=='\n') li=i+1;
i++;
}
m_children.append(new DocVerbatim(this,g_context,g_token->verb.mid(li),DocVerbatim::Code,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: code section ended without end marker");
doctokenizerYYsetStatePara();
return retval;
}
int DocPara::handleCommand(const QString &cmdName)
{
DBG(("handleCommand(%s)\n",cmdName.data()));
int retval = RetVal_OK;
switch (CmdMapper::map(cmdName))
switch (Mappers::cmdMapper->map(cmdName))
{
case CMD_UNKNOWN:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Found unknown command `\\%s'",cmdName.data());
......@@ -3910,17 +4176,7 @@ int DocPara::handleCommand(const QString &cmdName)
case CMD_STARTCODE:
{
doctokenizerYYsetStateCode();
retval = doctokenizerYYlex();
// search for the first non-whitespace line, index is stored in li
int i=0,li=0,l=g_token->verb.length();
while (i<l && g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n')
{
if (g_token->verb.at(i)=='\n') li=i+1;
i++;
}
m_children.append(new DocVerbatim(this,g_context,g_token->verb.mid(li),DocVerbatim::Code,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: code section ended without end marker");
doctokenizerYYsetStatePara();
retval = handleStartCode();
}
break;
case CMD_HTMLONLY:
......@@ -3988,7 +4244,7 @@ int DocPara::handleCommand(const QString &cmdName)
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
break;
case CMD_PARAM:
retval = handleParamSection(cmdName,DocParamSect::Param,g_token->paramDir);
retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,g_token->paramDir);
break;
case CMD_RETVAL:
retval = handleParamSection(cmdName,DocParamSect::RetVal);
......@@ -4150,12 +4406,31 @@ int DocPara::handleCommand(const QString &cmdName)
return retval;
}
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
const char *attrName,
QString *result)
{
HtmlAttribListIterator li(tagHtmlAttribs);
HtmlAttrib *opt;
for (li.toFirst();(opt=li.current());++li)
{
if (opt->name==attrName)
{
*result = opt->value;
return TRUE;
}
}
return FALSE;
}
int DocPara::handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tagHtmlAttribs)
{
DBG(("handleHtmlStartTag(%s,%d)\n",tagName.data(),tagHtmlAttribs.count()));
int retval=RetVal_OK;
int tagId = HtmlTagMapper::map(tagName);
int tagId = Mappers::htmlTagMapper->map(tagName);
if (g_token->emptyTag && !(tagId&XML_CmdMask) && tagId!=HTML_UNKNOWN)
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: HTML tags may not use the 'empty tag' XHTML syntax.");
switch (tagId)
{
case HTML_UL:
......@@ -4186,7 +4461,16 @@ int DocPara::handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tag
handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs);
break;
case HTML_CODE:
handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
if (g_fileName.right(3)==".cs")
// for C# code we treat <code> as an XML tag
{
doctokenizerYYsetStateXmlCode();
retval = handleStartCode();
}
else // normal HTML markup
{
handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
}
break;
case HTML_EMPHASIS:
handleStyleEnter(this,m_children,DocStyleChange::Italic,&g_token->attribs);
......@@ -4309,11 +4593,149 @@ int DocPara::handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tag
}
}
break;
case XML_SUMMARY:
case XML_REMARKS:
case XML_VALUE:
case XML_PARA:
if (!m_children.isEmpty())
{
retval = TK_NEWPARA;
}
break;
case XML_EXAMPLE:
case XML_DESCRIPTION:
break;
case XML_C:
handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
break;
case XML_PARAM:
{
QString paramName;
if (findAttribute(tagHtmlAttribs,"name",&paramName))
{
retval = handleParamSection(paramName,DocParamSect::Param,TRUE);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <param> tag.");
}
}
break;
case XML_PARAMREF:
{
QString paramName;
if (findAttribute(tagHtmlAttribs,"name",&paramName))
{
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
retval=handleStyleArgument(this,m_children,paramName);
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <paramref> tag.");
}
}
break;
case XML_EXCEPTION:
{
QString exceptName;
if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
{
retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <exception> tag.");
}
}
break;
case XML_ITEM:
if (!insideUL(this) && !insideOL(this))
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: lonely <item> tag found");
}
else
{
retval=RetVal_ListItem;
}
break;
case XML_RETURNS:
retval = handleSimpleSection(DocSimpleSect::Return,TRUE);
g_hasReturnCommand=TRUE;
break;
case XML_SEE:
// I'm not sure if <see> is the same as <seealso> or if it
// should you link a member without producing a section. The
// C# specification is extremely vague about this (but what else
// can we expect from Microsoft...)
{
QString cref;
if (findAttribute(tagHtmlAttribs,"cref",&cref))
{
DocRef *ref = new DocRef(this,cref);
m_children.append(ref);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'cref' attribute from <see> tag.");
}
}
break;
case XML_SEEALSO:
{
QString cref;
if (findAttribute(tagHtmlAttribs,"cref",&cref))
{
// Look for an existing "see" section
DocSimpleSect *ss=0;
QListIterator<DocNode> cli(m_children);
DocNode *n;
for (cli.toFirst();(n=cli.current());++cli)
{
if (n->kind()==Kind_SimpleSect && ((DocSimpleSect *)n)->type()==DocSimpleSect::See)
{
ss = (DocSimpleSect *)n;
}
}
if (!ss) // start new section
{
ss=new DocSimpleSect(this,DocSimpleSect::See);
m_children.append(ss);
}
ss->appendLinkWord(cref);
retval = RetVal_OK;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'cref' attribute from <seealso> tag.");
}
}
break;
case XML_LIST:
{
QString type;
DocHtmlList::Type listType = DocHtmlList::Unordered;
if (findAttribute(tagHtmlAttribs,"type",&type) && type=="number")
{
listType=DocHtmlList::Ordered;
}
DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,listType);
m_children.append(list);
retval=list->parseXml();
}
break;
case XML_INCLUDE:
case XML_PERMISSION:
// These tags are defined in .Net but are currently unsupported
break;
case HTML_UNKNOWN:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported html tag <%s> found", tagName.data());
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported xml/html tag <%s> found", tagName.data());
m_children.append(new DocWord(this, "<"+tagName+tagHtmlAttribs.toString()+">"));
break;
break;
default:
// we should not get here!
ASSERT(0);
......@@ -4325,7 +4747,7 @@ int DocPara::handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tag
int DocPara::handleHtmlEndTag(const QString &tagName)
{
DBG(("handleHtmlEndTag(%s)\n",tagName.data()));
int tagId = HtmlTagMapper::map(tagName);
int tagId = Mappers::htmlTagMapper->map(tagName);
int retval=RetVal_OK;
switch (tagId)
{
......@@ -4450,8 +4872,31 @@ int DocPara::handleHtmlEndTag(const QString &tagName)
//warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </a> found");
// ignore </a> tag (can be part of <a name=...></a>
break;
case XML_SUMMARY:
case XML_REMARKS:
case XML_PARA:
case XML_VALUE:
case XML_LIST:
case XML_EXAMPLE:
case XML_PARAM:
case XML_RETURNS:
case XML_SEEALSO:
case XML_EXCEPTION:
retval = RetVal_CloseXml;
break;
case XML_C:
handleStyleLeave(this,m_children,DocStyleChange::Code,"c");
break;
case XML_ITEM:
case XML_INCLUDE:
case XML_PERMISSION:
case XML_DESCRIPTION:
case XML_PARAMREF:
// These tags are defined in .Net but are currently unsupported
break;
case HTML_UNKNOWN:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported html tag </%s> found", tagName.data());
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported xml/html tag </%s> found", tagName.data());
m_children.append(new DocWord(this,"</"+tagName+">"));
break;
default:
......@@ -4610,7 +5055,7 @@ reparsetoken:
case TK_COMMAND:
{
// see if we have to start a simple section
int cmd = CmdMapper::map(g_token->name);
int cmd = Mappers::cmdMapper->map(g_token->name);
DocNode *n=parent();
while (n &&
n->kind()!=DocNode::Kind_SimpleSect &&
......@@ -4901,7 +5346,7 @@ void DocText::parse()
}
break;
case TK_COMMAND:
switch (CmdMapper::map(g_token->name))
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_BSLASH:
m_children.append(new DocSymbol(this,DocSymbol::BSlash));
......@@ -5173,8 +5618,8 @@ DocNode *validatingParseDoc(const char *fileName,int startLine,
// TODO: These should be called at the end of the program.
//doctokenizerYYcleanup();
//CmdMapper::freeInstance();
//HtmlTagMapper::freeInstance();
//Mappers::cmdMapper->freeInstance();
//Mappers::htmlTagMapper->freeInstance();
return root;
}
......
......@@ -885,6 +885,7 @@ class DocHtmlList : public CompAccept<DocHtmlList>, public DocNode
void accept(DocVisitor *v) { CompAccept<DocHtmlList>::accept(this,v); }
const HtmlAttribList &attribs() const { return m_attribs; }
int parse();
int parseXml();
private:
DocNode * m_parent;
......@@ -909,6 +910,8 @@ class DocSimpleSect : public CompAccept<DocSimpleSect>, public DocNode
void accept(DocVisitor *v);
int parse(bool userTitle);
int parseRcs();
int parseXml();
void appendLinkWord(const QString &word);
private:
DocNode * m_parent;
......@@ -930,7 +933,7 @@ class DocParamSect : public CompAccept<DocParamSect>, public DocNode
};
DocParamSect(DocNode *parent,Type t)
: m_parent(parent), m_type(t) {}
int parse(const QString &cmdName,Direction d);
int parse(const QString &cmdName,bool xmlContext,Direction d);
Kind kind() const { return Kind_ParamSect; }
Type type() const { return m_type; }
DocNode *parent() const { return m_parent; }
......@@ -962,9 +965,10 @@ class DocPara : public CompAccept<DocPara>, public DocNode
int handleCommand(const QString &cmdName);
int handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tagHtmlAttribs);
int handleHtmlEndTag(const QString &tagName);
int handleSimpleSection(DocSimpleSect::Type t);
int handleSimpleSection(DocSimpleSect::Type t,bool xmlContext=FALSE);
int handleXRefItem();
int handleParamSection(const QString &cmdName,DocParamSect::Type t,
bool xmlContext,
int direction);
void handleIncludeOperator(const QString &cmdName,DocIncOperator::Type t);
void handleImage(const QString &cmdName);
......@@ -973,7 +977,9 @@ class DocPara : public CompAccept<DocPara>, public DocNode
void handleLink(const QString &cmdName,bool isJavaLink);
void handleRef(const QString &cmdName);
void handleSection(const QString &cmdName);
int handleStartCode();
int handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level);
bool injectToken(int tok,const QString &tokText);
//int handleLanguageSwitch();
private:
......@@ -989,11 +995,10 @@ class DocParamList : public DocNode
public:
DocParamList(DocNode *parent,DocParamSect::Type t,DocParamSect::Direction d)
: m_parent(parent) , m_type(t), m_dir(d), m_isFirst(TRUE), m_isLast(TRUE)
{ m_paragraph=new DocPara(this); }
virtual ~DocParamList() { delete m_paragraph; }
{ m_paragraphs.setAutoDelete(TRUE); }
virtual ~DocParamList() { }
Kind kind() const { return Kind_ParamList; }
DocNode *parent() const { return m_parent; }
//const QStrList &parameters() { return m_params; }
const QList<DocNode> &parameters() { return m_params; }
DocParamSect::Type type() const { return m_type; }
DocParamSect::Direction direction() const { return m_dir; }
......@@ -1004,15 +1009,17 @@ class DocParamList : public DocNode
void accept(DocVisitor *v)
{
v->visitPre(this);
m_paragraph->accept(v);
QListIterator<DocPara> cli(m_paragraphs);
DocNode *n;
for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
v->visitPost(this);
}
int parse(const QString &cmdName);
int parseXml(const QString &paramName);
private:
DocNode * m_parent;
DocPara * m_paragraph;
//QStrList m_params;
QList<DocPara> m_paragraphs;
QList<DocNode> m_params;
DocParamSect::Type m_type;
DocParamSect::Direction m_dir;
......@@ -1078,6 +1085,7 @@ class DocHtmlListItem : public CompAccept<DocHtmlListItem>, public DocNode
DocNode *parent() const { return m_parent; }
void accept(DocVisitor *v) { CompAccept<DocHtmlListItem>::accept(this,v); }
int parse();
int parseXml();
private:
DocNode * m_parent;
......
......@@ -57,7 +57,8 @@ enum Tokens
RetVal_TableHCell = 0x1000E,
RetVal_EndTable = 0x1000F,
RetVal_Internal = 0x10010,
RetVal_SwitchLang = 0x10011
RetVal_SwitchLang = 0x10011,
RetVal_CloseXml = 0x10012
};
struct TokenInfo
......@@ -92,6 +93,7 @@ struct TokenInfo
// html tag
HtmlAttribList attribs;
bool endTag;
bool emptyTag;
// whitespace
QString chars;
......@@ -124,6 +126,7 @@ void doctokenizerYYsetStatePara();
void doctokenizerYYsetStateTitle();
void doctokenizerYYsetStateTitleAttrValue();
void doctokenizerYYsetStateCode();
void doctokenizerYYsetStateXmlCode();
void doctokenizerYYsetStateHtmlOnly();
void doctokenizerYYsetStateManOnly();
void doctokenizerYYsetStateLatexOnly();
......
......@@ -136,72 +136,6 @@ static int computeIndent(const char *str,int length)
return indent;
}
/*! converts input string \a opt into a list of Html Attributes. Each
* attribute is a name, value pair. The result is stored in g_token->attribs
*/
static void parseHtmlAttribs(const char *att)
{
//printf("parseHtmlAttribs(%s)\n",att);
QCString attribs=att;
int len = attribs.length();
char c;
int i=0,startName,endName,startAttrib,endAttrib;
while (i<len)
{
c=attribs.at(i);
// skip spaces
while (i<len && c==' ') { c=attribs.at(++i); }
startName=i;
// search for end of name
while (i<len && c!=' ' && c!='=') { c=attribs.at(++i); }
endName=i;
HtmlAttrib opt;
opt.name = attribs.mid(startName,endName-startName).lower();
// skip spaces
while (i<len && c==' ') { c=attribs.at(++i); }
if (attribs.at(i)=='=') // option has value
{
c=attribs.at(++i);
// skip spaces
while (i<len && c==' ') { c=attribs.at(++i); }
if (attribs.at(i)=='\'') // option '...'
{
c=attribs.at(++i);
startAttrib=i;
// search for matching quote
while (i<len && c!='\'') { c=attribs.at(++i); }
endAttrib=i;
if (i<len) c=attribs.at(++i);
}
else if (attribs.at(i)=='"') // option "..."
{
c=attribs.at(++i);
startAttrib=i;
// search for matching quote
while (i<len && c!='"') { c=attribs.at(++i); }
endAttrib=i;
if (i<len) c=attribs.at(++i);
}
else // value without any quotes
{
startAttrib=i;
// search for separator
while (i<len && c!=' ') { c=attribs.at(++i); }
endAttrib=i;
if (i<len) c=attribs.at(++i);
}
opt.value = attribs.mid(startAttrib,endAttrib-startAttrib);
}
else // start next option
{
}
//printf("=====> Adding option name=<%s> value=<%s>\n",
// opt.name.data(),opt.value.data());
g_token->attribs.append(&opt);
}
}
//--------------------------------------------------------------------------
static void processSection()
......@@ -231,27 +165,96 @@ static void processSection()
static void handleHtmlTag()
{
g_token->name = yytext;
QCString tagText=yytext;
g_token->attribs.clear();
g_token->endTag = FALSE;
g_token->emptyTag = FALSE;
// Check for end tag
int startNamePos=1;
if (g_token->name.at(1)=='/') startNamePos++;
int attSep=0;
while (attSep<yyleng && !isspace(yytext[attSep]))
if (tagText.at(1)=='/')
{
attSep++;
g_token->endTag = TRUE;
startNamePos++;
}
if (attSep!=yyleng) // tag has one or more options
// Parse the name portion
int i = startNamePos;
for (i=startNamePos; i < yyleng; i++)
{
parseHtmlAttribs(g_token->name.mid(attSep+1,g_token->name.length()-attSep-2));
g_token->name=g_token->name.mid(startNamePos,attSep-1).lower();
// Check for valid HTML/XML name chars (including namespaces)
char c = tagText.at(i);
if (!(isalnum(c) || c=='-' || c=='_' || c==':')) break;
}
else // tag without options, strip brackets
g_token->name = tagText.mid(startNamePos,i-startNamePos);
// Parse the attributes. Each attribute is a name, value pair
// The result is stored in g_token->attribs.
int startName,endName,startAttrib,endAttrib;
while (i<yyleng)
{
g_token->name=g_token->name.mid(startNamePos,g_token->name.length()-startNamePos-1).lower();
char c=tagText.at(i);
// skip spaces
while (i<yyleng && c==' ') { c=tagText.at(++i); }
// check for end of the tag
if (c == '>') break;
// Check for XML style "empty" tag.
if (c == '/')
{
g_token->emptyTag = TRUE;
break;
}
startName=i;
// search for end of name
while (i<yyleng && c!=' ' && c!='=') { c=tagText.at(++i); }
endName=i;
HtmlAttrib opt;
opt.name = tagText.mid(startName,endName-startName).lower();
// skip spaces
while (i<yyleng && c==' ') { c=tagText.at(++i); }
if (tagText.at(i)=='=') // option has value
{
c=tagText.at(++i);
// skip spaces
while (i<yyleng && c==' ') { c=tagText.at(++i); }
if (tagText.at(i)=='\'') // option '...'
{
c=tagText.at(++i);
startAttrib=i;
// search for matching quote
while (i<yyleng && c!='\'') { c=tagText.at(++i); }
endAttrib=i;
if (i<yyleng) c=tagText.at(++i);
}
else if (tagText.at(i)=='"') // option "..."
{
c=tagText.at(++i);
startAttrib=i;
// search for matching quote
while (i<yyleng && c!='"') { c=tagText.at(++i); }
endAttrib=i;
if (i<yyleng) c=tagText.at(++i);
}
else // value without any quotes
{
startAttrib=i;
// search for separator
while (i<yyleng && c!=' ') { c=tagText.at(++i); }
endAttrib=i;
if (i<yyleng) c=tagText.at(++i);
}
opt.value = tagText.mid(startAttrib,endAttrib-startAttrib);
}
else // start next option
{
}
//printf("=====> Adding option name=<%s> value=<%s>\n",
// opt.name.data(),opt.value.data());
g_token->attribs.append(&opt);
}
g_token->endTag = startNamePos==2;
}
static QString stripEmptyLines(const char *s)
{
int result=0,p=0;
......@@ -287,6 +290,7 @@ WS [ \t\r\n]
NONWS [^ \t\r\n]
BLANK [ \t\r]
ID [a-z_A-Z][a-z_A-Z0-9]*
MAILADR [a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
OPTSTARS ("//"{BLANK}*)?"*"*{BLANK}*
LISTITEM {BLANK}*{OPTSTARS}"-"("#")?{WS}
ENDLIST {BLANK}*{OPTSTARS}"."{BLANK}*\n
......@@ -326,7 +330,7 @@ WORD1 "%"?{CHARWORD}+|"{"|"}"|("\""[^"\n]*"\"")
WORD2 "."|","|"("|")"|"["|"]"|":"|";"|"\?"
WORD1NQ "%"?{CHARWORDQ}+
WORD2NQ "."|","|"("|")"|"["|"]"|":"|";"|"\?"
HTMLTAG "<"(("/")?){ID}({WS}+{ATTRIB})*{WS}*">"
HTMLTAG "<"(("/")?){ID}({WS}+{ATTRIB})*{WS}*(("/")?)">"
HTMLKEYL "strong"|"center"|"table"|"caption"|"small"|"code"|"dfn"|"var"|"img"|"pre"|"sub"|"sup"|"tr"|"td"|"th"|"ol"|"ul"|"li"|"tt"|"kbd"|"em"|"hr"|"dl"|"dt"|"dd"|"br"|"i"|"a"|"b"|"p"
HTMLKEYU "STRONG"|"CENTER"|"TABLE"|"CAPTION"|"SMALL"|"CODE"|"DFN"|"VAR"|"IMG"|"PRE"|"SUB"|"SUP"|"TR"|"TD"|"TH"|"OL"|"UL"|"LI"|"TT"|"KBD"|"EM"|"HR"|"DL"|"DT"|"DD"|"BR"|"I"|"A"|"B"|"P"
HTMLKEYW {HTMLKEYL}|{HTMLKEYU}
......@@ -344,6 +348,7 @@ REFWORD ("#"|"::")?({ID}("."|"#"|"::"|"-"))*({ID}(":")?){FUNCARG}?
%x St_TitleA
%x St_TitleV
%x St_Code
%x St_XmlCode
%x St_HtmlOnly
%x St_ManOnly
%x St_LatexOnly
......@@ -445,7 +450,7 @@ REFWORD ("#"|"::")?({ID}("."|"#"|"::"|"-"))*({ID}(":")?){FUNCARG}?
g_token->isEMailAddr=FALSE;
return TK_URL;
}
<St_Para>[a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+ { // Mail address
<St_Para>{MAILADR} { // Mail address
g_token->name=yytext;
g_token->isEMailAddr=TRUE;
return TK_URL;
......@@ -539,9 +544,12 @@ REFWORD ("#"|"::")?({ID}("."|"#"|"::"|"-"))*({ID}(":")?){FUNCARG}?
<St_Code>{WS}*{CMD}"endcode" {
return RetVal_OK;
}
<St_Code>[^\\@\n]+ |
<St_Code>\n |
<St_Code>. {
<St_XmlCode>{WS}*"</code>" {
return RetVal_OK;
}
<St_Code,St_XmlCode>[^\\@\n]+ |
<St_Code,St_XmlCode>\n |
<St_Code,St_XmlCode>. {
g_token->verb+=yytext;
}
<St_HtmlOnly>{CMD}"endhtmlonly" {
......@@ -942,6 +950,12 @@ void doctokenizerYYsetStateCode()
BEGIN(St_Code);
}
void doctokenizerYYsetStateXmlCode()
{
g_token->verb="";
BEGIN(St_XmlCode);
}
void doctokenizerYYsetStateHtmlOnly()
{
g_token->verb="";
......
......@@ -24,7 +24,6 @@
#include "util.h"
#include "config.h"
#include "language.h"
#include "scanner.h"
#include "defargs.h"
#include "docparser.h"
#include "debug.h"
......
......@@ -36,7 +36,6 @@
#include "logos.h"
#include "instdox.h"
#include "message.h"
#include "code.h"
#include "config.h"
#include "util.h"
#include "pre.h"
......@@ -67,6 +66,7 @@
#include "searchindex.h"
#include "parserintf.h"
#include "htags.h"
#include "pyscanner.h"
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define popen _popen
......@@ -125,6 +125,7 @@ QDict<int> * Doxygen::htmlDirMap = 0;
QCache<LookupInfo> Doxygen::lookupCache(20000,20000);
DirSDict Doxygen::directories(17);
SDict<DirRelation> Doxygen::dirRelations(257);
ParserManager *Doxygen::parserManager = 0;
static StringList inputFiles;
static StringDict excludeNameDict(1009); // sections
......@@ -7310,60 +7311,8 @@ static void copyStyleSheet()
}
}
#if 0
static void readFiles(const QCString &tmpFile)
{
QFile outFile(tmpFile);
if (outFile.open(IO_WriteOnly))
{
QTextStream out(&outFile);
QCString *s=inputFiles.first();
while (s)
{
QCString fileName=*s;
//bool multiLineIsBrief = Config_getBool("MULTILINE_CPP_IS_BRIEF");
out << (char)6;
out << fileName;
out << (char)6;
out << '\n';
QFileInfo fi(fileName);
BufStr preBuf(fi.size()+4096);
BufStr *bufPtr = &preBuf;
if (Config_getBool("ENABLE_PREPROCESSING"))
{
msg("Preprocessing %s...\n",s->data());
preprocessFile(fileName,*bufPtr);
}
else
{
msg("Reading %s...\n",s->data());
copyAndFilterFile(fileName,*bufPtr);
}
bufPtr->addChar('\n'); /* to prevent problems under Windows ? */
BufStr convBuf(bufPtr->curPos()+1024);
convertCppComments(&preBuf,&convBuf,fileName);
out.writeRawBytes(convBuf.data(),convBuf.curPos());
s=inputFiles.next();
//printf("-------> adding new line\n");
}
}
}
#endif
static void parseFiles(Entry *root)
{
ParserInterface *defaultParser = new CLanguageScanner;
ParserManager *parserManager = new ParserManager(defaultParser);
// register any additional parsers here...
QCString *s=inputFiles.first();
while (s)
......@@ -7372,12 +7321,14 @@ static void parseFiles(Entry *root)
QCString extension;
int ei = fileName.findRev('.');
if (ei!=-1) extension=fileName.right(fileName.length()-ei);
ParserInterface *parser = Doxygen::parserManager->getParser(extension);
QFileInfo fi(fileName);
BufStr preBuf(fi.size()+4096);
BufStr *bufPtr = &preBuf;
if (Config_getBool("ENABLE_PREPROCESSING"))
if (Config_getBool("ENABLE_PREPROCESSING") &&
parser->needsPreprocessing(extension))
{
msg("Preprocessing %s...\n",s->data());
preprocessFile(fileName,*bufPtr);
......@@ -7396,8 +7347,7 @@ static void parseFiles(Entry *root)
convBuf.addChar('\0');
ParserInterface *parser = parserManager->getParser(extension);
parser->parse(fileName,convBuf.data(),root);
parser->parseInput(fileName,convBuf.data(),root);
s=inputFiles.next();
}
......@@ -7792,6 +7742,12 @@ void initDoxygen()
Doxygen::runningTime.start();
initPreprocessor();
ParserInterface *defaultParser = new CLanguageScanner;
Doxygen::parserManager = new ParserManager(defaultParser);
Doxygen::parserManager->registerParser(".py",new PythonLanguageScanner);
// register any additional parsers here...
Doxygen::sectionDict.setAutoDelete(TRUE);
Doxygen::inputNameList.setAutoDelete(TRUE);
Doxygen::memberNameSDict.setAutoDelete(TRUE);
......@@ -7820,13 +7776,13 @@ void cleanUpDoxygen()
delete Doxygen::exampleSDict;
delete Doxygen::globalScope;
delete Doxygen::xrefLists;
delete Doxygen::parserManager;
cleanUpPreprocessor();
Config::deleteInstance();
QTextCodec::deleteAllCodecs();
delete theTranslator;
delete outputList;
CmdMapper::freeInstance();
HtmlTagMapper::freeInstance();
Mappers::freeMappers();
//delete Doxygen::symbolMap; <- we cannot do this unless all static lists
// (such as Doxygen::namespaceSDict)
// with objects based on Definition are made
......
......@@ -42,6 +42,7 @@ class PageSDict;
class PageDef;
class SearchIndex;
class DirDef;
class ParserManager;
typedef QList<QCString> StringList;
typedef QDict<FileDef> FileDict;
......@@ -116,6 +117,7 @@ class Doxygen
static QCache<LookupInfo> lookupCache;
static DirSDict directories;
static SDict<DirRelation> dirRelations;
static ParserManager *parserManager;
};
void initDoxygen();
......
......@@ -28,18 +28,18 @@
#include "outputlist.h"
#include "dot.h"
#include "message.h"
#include "code.h"
#include "docparser.h"
#include "ftvhelp.h"
#include "searchindex.h"
#include "htags.h"
#include "parserintf.h"
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define popen _popen
#define pclose _pclose
#endif
class DevNullCodeDocInterface : public BaseCodeDocInterface
class DevNullCodeDocInterface : public CodeOutputInterface
{
public:
virtual void codify(const char *) {}
......@@ -653,9 +653,10 @@ void FileDef::writeSource(OutputList &ol)
ol.endTextLink();
}
initParseCodeContext();
ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
pIntf->resetCodeParserState();
ol.startCodeFragment();
parseCode(ol,0,
pIntf->parseCode(ol,0,
fileToString(absFilePath(),Config_getBool("FILTER_SOURCE_FILES")),
FALSE,0,this
);
......@@ -667,7 +668,10 @@ void FileDef::writeSource(OutputList &ol)
void FileDef::parseSource()
{
DevNullCodeDocInterface devNullIntf;
parseCode(devNullIntf,0,
ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
pIntf->resetCodeParserState();
pIntf->parseCode(
devNullIntf,0,
fileToString(absFilePath(),Config_getBool("FILTER_SOURCE_FILES")),
FALSE,0,this
);
......
......@@ -22,11 +22,11 @@
#include "language.h"
#include "doxygen.h"
#include "outputgen.h"
#include "code.h"
#include "dot.h"
#include "message.h"
#include "config.h"
#include "htmlgen.h"
#include "parserintf.h"
static const int NUM_HTML_LIST_TYPES = 4;
......@@ -49,8 +49,10 @@ static QString htmlAttribsToString(const HtmlAttribList &attribs)
//-------------------------------------------------------------------------
HtmlDocVisitor::HtmlDocVisitor(QTextStream &t,BaseCodeDocInterface &ci)
: DocVisitor(DocVisitor_Html), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE)
HtmlDocVisitor::HtmlDocVisitor(QTextStream &t,CodeOutputInterface &ci,
const char *langExt)
: DocVisitor(DocVisitor_Html), m_t(t), m_ci(ci), m_insidePre(FALSE),
m_hide(FALSE), m_langExt(langExt)
{
}
......@@ -196,7 +198,9 @@ void HtmlDocVisitor::visit(DocVerbatim *s)
{
case DocVerbatim::Code: // fall though
m_t << PREFRAG_START;
parseCode(m_ci,s->context(),s->text().latin1(),s->isExample(),s->exampleFile());
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,s->context(),s->text().latin1(),
s->isExample(),s->exampleFile());
m_t << PREFRAG_END;
break;
case DocVerbatim::Verbatim:
......@@ -253,7 +257,9 @@ void HtmlDocVisitor::visit(DocInclude *inc)
{
case DocInclude::Include:
m_t << PREFRAG_START;
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile());
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,inc->context(),inc->text().latin1(),
inc->isExample(),inc->exampleFile());
m_t << PREFRAG_END;
break;
case DocInclude::IncWithLines:
......@@ -261,7 +267,11 @@ void HtmlDocVisitor::visit(DocInclude *inc)
m_t << PREFRAG_START;
QFileInfo cfi( inc->file() );
FileDef fd( cfi.dirPath(), cfi.fileName() );
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),
inc->isExample(),
inc->exampleFile(), &fd);
m_t << PREFRAG_END;
}
break;
......@@ -291,7 +301,13 @@ void HtmlDocVisitor::visit(DocIncOperator *op)
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
if (!m_hide) parseCode(m_ci,op->context(),op->text().latin1(),op->isExample(),op->exampleFile());
if (!m_hide)
{
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,op->context(),
op->text().latin1(),op->isExample(),
op->exampleFile());
}
pushEnabled();
m_hide=TRUE;
}
......
......@@ -21,16 +21,17 @@
#include "docvisitor.h"
#include <qstack.h>
#include <qcstring.h>
class QTextStream;
class BaseCodeDocInterface;
class CodeOutputInterface;
class QString;
/*! @brief Concrete visitor implementation for HTML output. */
class HtmlDocVisitor : public DocVisitor
{
public:
HtmlDocVisitor(QTextStream &t,BaseCodeDocInterface &ci);
HtmlDocVisitor(QTextStream &t,CodeOutputInterface &ci,const char *langExt);
//--------------------------------------
// visitor functions for leaf nodes
......@@ -77,8 +78,6 @@ class HtmlDocVisitor : public DocVisitor
void visitPost(DocHtmlList *) ;
void visitPre(DocHtmlListItem *);
void visitPost(DocHtmlListItem *);
//void visitPre(DocHtmlPre *);
//void visitPost(DocHtmlPre *);
void visitPre(DocHtmlDescList *);
void visitPost(DocHtmlDescList *);
void visitPre(DocHtmlDescTitle *);
......@@ -111,8 +110,6 @@ class HtmlDocVisitor : public DocVisitor
void visitPost(DocSecRefItem *);
void visitPre(DocSecRefList *);
void visitPost(DocSecRefList *);
//void visitPre(DocLanguage *);
//void visitPost(DocLanguage *);
void visitPre(DocParamSect *);
void visitPost(DocParamSect *);
void visitPre(DocParamList *);
......@@ -147,10 +144,11 @@ class HtmlDocVisitor : public DocVisitor
//--------------------------------------
QTextStream &m_t;
BaseCodeDocInterface &m_ci;
CodeOutputInterface &m_ci;
bool m_insidePre;
bool m_hide;
QStack<bool> m_enabled;
QCString m_langExt;
};
#endif
......@@ -1418,9 +1418,9 @@ void HtmlGenerator::endParamList()
t << "</dl>";
}
void HtmlGenerator::printDoc(DocNode *n)
void HtmlGenerator::printDoc(DocNode *n,const char *langExt)
{
HtmlDocVisitor *visitor = new HtmlDocVisitor(t,*this);
HtmlDocVisitor *visitor = new HtmlDocVisitor(t,*this,langExt);
n->accept(visitor);
delete visitor;
}
......
......@@ -45,7 +45,7 @@ class HtmlGenerator : public OutputGenerator
bool isEnabled(OutputType o) { return (o==Html && active); }
OutputGenerator *get(OutputType o) { return (o==Html) ? this : 0; }
void printDoc(DocNode *);
void printDoc(DocNode *,const char *);
void startFile(const char *name,const char *manName,const char *title);
void writeFooter();
......
......@@ -25,7 +25,6 @@
#include "message.h"
#include "index.h"
#include "doxygen.h"
#include "code.h"
#include "config.h"
#include "filedef.h"
#include "outputlist.h"
......
......@@ -21,10 +21,10 @@
#include "language.h"
#include "doxygen.h"
#include "outputgen.h"
#include "code.h"
#include "dot.h"
#include "util.h"
#include "message.h"
#include "parserintf.h"
static QString escapeLabelName(const char *s)
{
......@@ -79,10 +79,11 @@ QString LatexDocVisitor::escapeMakeIndexChars(const char *s)
}
LatexDocVisitor::LatexDocVisitor(QTextStream &t,BaseCodeDocInterface &ci,
bool insideTabbing)
LatexDocVisitor::LatexDocVisitor(QTextStream &t,CodeOutputInterface &ci,
const char *langExt,bool insideTabbing)
: DocVisitor(DocVisitor_Latex), m_t(t), m_ci(ci), m_insidePre(FALSE),
m_insideItem(FALSE), m_hide(FALSE), m_insideTabbing(insideTabbing)
m_insideItem(FALSE), m_hide(FALSE), m_insideTabbing(insideTabbing),
m_langExt(langExt)
{
}
......@@ -251,7 +252,9 @@ void LatexDocVisitor::visit(DocVerbatim *s)
{
case DocVerbatim::Code:
m_t << "\n\n\\footnotesize\\begin{verbatim}";
parseCode(m_ci,s->context(),s->text().latin1(),s->isExample(),s->exampleFile());
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,s->context(),s->text().latin1(),
s->isExample(),s->exampleFile());
m_t << "\\end{verbatim}\n\\normalsize" << endl;
break;
case DocVerbatim::Verbatim:
......@@ -316,13 +319,20 @@ void LatexDocVisitor::visit(DocInclude *inc)
m_t << "\n\n\\footnotesize\\begin{verbatim}";
QFileInfo cfi( inc->file() );
FileDef fd( cfi.dirPath(), cfi.fileName() );
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),
inc->isExample(),
inc->exampleFile(), &fd);
m_t << "\\end{verbatim}\n\\normalsize" << endl;
}
break;
case DocInclude::Include:
m_t << "\n\n\\footnotesize\\begin{verbatim}";
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile());
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),inc->isExample(),
inc->exampleFile());
m_t << "\\end{verbatim}\n\\normalsize" << endl;
break;
case DocInclude::DontInclude:
......@@ -350,7 +360,12 @@ void LatexDocVisitor::visit(DocIncOperator *op)
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
if (!m_hide) parseCode(m_ci,op->context(),op->text().latin1(),op->isExample(),op->exampleFile());
if (!m_hide)
{
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,op->context(),op->text().latin1(),
op->isExample(),op->exampleFile());
}
pushEnabled();
m_hide=TRUE;
}
......
......@@ -21,16 +21,18 @@
#include "docvisitor.h"
#include <qstack.h>
#include <qcstring.h>
class QTextStream;
class BaseCodeDocInterface;
class CodeOutputInterface;
class QString;
/*! @brief Concrete visitor implementation for LaTeX output. */
class LatexDocVisitor : public DocVisitor
{
public:
LatexDocVisitor(QTextStream &t,BaseCodeDocInterface &ci,bool insideTabbing);
LatexDocVisitor(QTextStream &t,CodeOutputInterface &ci,
const char *langExt,bool insideTabbing);
//--------------------------------------
// visitor functions for leaf nodes
......@@ -150,12 +152,13 @@ class LatexDocVisitor : public DocVisitor
//--------------------------------------
QTextStream &m_t;
BaseCodeDocInterface &m_ci;
CodeOutputInterface &m_ci;
bool m_insidePre;
bool m_insideItem;
bool m_hide;
bool m_insideTabbing;
QStack<bool> m_enabled;
QCString m_langExt;
};
#endif
......@@ -1542,9 +1542,9 @@ void LatexGenerator::endParamList()
}
void LatexGenerator::printDoc(DocNode *n)
void LatexGenerator::printDoc(DocNode *n,const char *langExt)
{
LatexDocVisitor *visitor = new LatexDocVisitor(t,*this,insideTabbing);
LatexDocVisitor *visitor = new LatexDocVisitor(t,*this,langExt,insideTabbing);
n->accept(visitor);
delete visitor;
}
......
......@@ -43,7 +43,7 @@ class LatexGenerator : public OutputGenerator
bool isEnabled(OutputType o) { return (o==Latex && active); }
OutputGenerator *get(OutputType o) { return (o==Latex) ? this : 0; }
void printDoc(DocNode *);
void printDoc(DocNode *,const char *);
void startFile(const char *name,const char *manName,const char *title);
void writeFooter() {}
......
......@@ -75,6 +75,8 @@ HEADERS = bufstr.h \
pngenc.h \
pre.h \
printdocvisitor.h \
pycode.h \
pyscanner.h \
qtbc.h \
reflist.h \
rtfdocvisitor.h \
......@@ -176,6 +178,8 @@ SOURCES = ce_lex.cpp \
perlmodgen.cpp \
pngenc.cpp \
pre.cpp \
pycode.cpp \
pyscanner.cpp \
reflist.cpp \
rtfdocvisitor.cpp \
rtfgen.cpp \
......
......@@ -51,6 +51,12 @@ sub GenerateDep {
#$ GenerateDep("code.cpp","code.l");
$(LEX) -PcodeYY -t code.l | $(INCBUFSIZE) >code.cpp
#$ GenerateDep("pyscanner.cpp","pyscanner.l");
$(LEX) -PpyscanYY -t pyscanner.l | $(INCBUFSIZE) >pyscanner.cpp
#$ GenerateDep("pycode.cpp","pycode.l");
$(LEX) -PpycodeYY -t pycode.l | $(INCBUFSIZE) >pycode.cpp
#$ GenerateDep("pre.cpp","pre.l");
$(LEX) -PpreYY -t pre.l | $(INCBUFSIZE) >pre.cpp
......
......@@ -26,10 +26,12 @@
#include "util.h"
#include "message.h"
#include <qfileinfo.h>
#include "parserintf.h"
ManDocVisitor::ManDocVisitor(QTextStream &t,BaseCodeDocInterface &ci)
ManDocVisitor::ManDocVisitor(QTextStream &t,CodeOutputInterface &ci,
const char *langExt)
: DocVisitor(DocVisitor_Man), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE), m_firstCol(TRUE),
m_indent(0)
m_indent(0), m_langExt(langExt)
{
}
......@@ -186,7 +188,9 @@ void ManDocVisitor::visit(DocVerbatim *s)
if (!m_firstCol) m_t << endl;
m_t << ".PP" << endl;
m_t << ".nf" << endl;
parseCode(m_ci,s->context(),s->text().latin1(),s->isExample(),s->exampleFile());
Doxygen::parserManager->getParser(0/*TODO*/)
->parseCode(m_ci,s->context(),s->text().latin1(),
s->isExample(),s->exampleFile());
if (!m_firstCol) m_t << endl;
m_t << ".fi" << endl;
m_t << ".PP" << endl;
......@@ -231,7 +235,11 @@ void ManDocVisitor::visit(DocInclude *inc)
m_t << ".nf" << endl;
QFileInfo cfi( inc->file() );
FileDef fd( cfi.dirPath(), cfi.fileName() );
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
Doxygen::parserManager->getParser(0/*TODO*/)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),
inc->isExample(),
inc->exampleFile(), &fd);
if (!m_firstCol) m_t << endl;
m_t << ".fi" << endl;
m_t << ".PP" << endl;
......@@ -242,7 +250,10 @@ void ManDocVisitor::visit(DocInclude *inc)
if (!m_firstCol) m_t << endl;
m_t << ".PP" << endl;
m_t << ".nf" << endl;
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile());
Doxygen::parserManager->getParser(0/*TODO*/)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),inc->isExample(),
inc->exampleFile());
if (!m_firstCol) m_t << endl;
m_t << ".fi" << endl;
m_t << ".PP" << endl;
......@@ -283,7 +294,12 @@ void ManDocVisitor::visit(DocIncOperator *op)
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
if (!m_hide) parseCode(m_ci,op->context(),op->text().latin1(),op->isExample(),op->exampleFile());
if (!m_hide)
{
Doxygen::parserManager->getParser(0/*TODO*/)
->parseCode(m_ci,op->context(),op->text().latin1(),
op->isExample(),op->exampleFile());
}
pushEnabled();
m_hide=TRUE;
}
......
......@@ -21,16 +21,17 @@
#include "docvisitor.h"
#include <qstack.h>
#include <qcstring.h>
class QTextStream;
class BaseCodeDocInterface;
class CodeOutputInterface;
class QString;
/*! @brief Concrete visitor implementation for LaTeX output. */
class ManDocVisitor : public DocVisitor
{
public:
ManDocVisitor(QTextStream &t,BaseCodeDocInterface &ci);
ManDocVisitor(QTextStream &t,CodeOutputInterface &ci,const char *langExt);
//--------------------------------------
// visitor functions for leaf nodes
......@@ -142,12 +143,13 @@ class ManDocVisitor : public DocVisitor
//--------------------------------------
QTextStream &m_t;
BaseCodeDocInterface &m_ci;
CodeOutputInterface &m_ci;
bool m_insidePre;
bool m_hide;
bool m_firstCol;
int m_indent;
QStack<bool> m_enabled;
QCString m_langExt;
};
#endif
......@@ -627,9 +627,9 @@ void ManGenerator::endParamList()
{
}
void ManGenerator::printDoc(DocNode *n)
void ManGenerator::printDoc(DocNode *n,const char *langExt)
{
ManDocVisitor *visitor = new ManDocVisitor(t,*this);
ManDocVisitor *visitor = new ManDocVisitor(t,*this,langExt);
n->accept(visitor);
delete visitor;
firstCol=FALSE;
......
......@@ -40,7 +40,7 @@ class ManGenerator : public OutputGenerator
bool isEnabled(OutputType o) { return (o==Man && active); }
OutputGenerator *get(OutputType o) { return (o==Man) ? this : 0; }
void printDoc(DocNode *);
void printDoc(DocNode *,const char *);
static void init();
void startFile(const char *name,const char *manName,const char *title);
......
......@@ -33,6 +33,7 @@
#include "docparser.h"
#include "dot.h"
#include "searchindex.h"
#include "parserintf.h"
//-----------------------------------------------------------------------------
......@@ -1577,9 +1578,10 @@ void MemberDef::writeDocumentation(MemberList *ml,OutputList &ol,
else
ol.parseText(theTranslator->trInitialValue());
ol.endBold();
initParseCodeContext();
ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
pIntf->resetCodeParserState();
ol.startCodeFragment();
parseCode(ol,scopeName,init,FALSE,0);
pIntf->parseCode(ol,scopeName,init,FALSE,0);
ol.endCodeFragment();
}
......
......@@ -24,7 +24,6 @@
#include "namespacedef.h"
#include "filedef.h"
#include "language.h"
#include "scanner.h"
#include "groupdef.h"
#include "doxygen.h"
#include "docparser.h"
......
......@@ -39,7 +39,7 @@ class GroupDef;
/*! \brief Output interface for code parser.
*/
class BaseCodeDocInterface
class CodeOutputInterface
{
public:
/*! Writes an ASCII string to the output. This function should keep
......@@ -78,7 +78,7 @@ class BaseCodeDocInterface
* or a list of formats (see OutputList). This interface
* contains functions that generate fragments of the output.
*/
class BaseOutputDocInterface : public BaseCodeDocInterface
class BaseOutputDocInterface : public CodeOutputInterface
{
public:
enum ParamListTypes { Param, RetVal, Exception };
......@@ -272,7 +272,7 @@ class OutputGenerator : public BaseOutputDocInterface
void pushGeneratorState();
void popGeneratorState();
virtual void printDoc(DocNode *) = 0;
virtual void printDoc(DocNode *,const char *langExt) = 0;
///////////////////////////////////////////////////////////////
// structural output interface
......
......@@ -26,6 +26,7 @@
#include "outputgen.h"
#include "config.h"
#include "message.h"
#include "definition.h"
#include "docparser.h"
......@@ -163,7 +164,9 @@ void OutputList::parseDoc(const char *fileName,int startLine,
og=outputs->first();
while (og)
{
if (og->isEnabled()) og->printDoc(root);
//printf("og->printDoc(extension=%s)\n",
// ctx?ctx->getDefFileExtension().data():"<null>");
if (og->isEnabled()) og->printDoc(root,ctx?ctx->getDefFileExtension():0);
og=outputs->next();
}
......@@ -186,7 +189,7 @@ void OutputList::parseText(const QCString &textStr)
og=outputs->first();
while (og)
{
if (og->isEnabled()) og->printDoc(root);
if (og->isEnabled()) og->printDoc(root,0);
og=outputs->next();
}
......
......@@ -21,6 +21,9 @@
#include <qdict.h>
class Entry;
class FileDef;
class CodeOutputInterface;
class MemberDef;
/** \brief Abstract interface for programming language parsers.
*
......@@ -31,13 +34,58 @@ class Entry;
class ParserInterface
{
public:
/** Parses a single file.
/** Parses a single input file with the goal to build an Entry tree.
* @param[in] fileName The full name of the file.
* @param[in] fileBuf The contents of the file (zero terminated).
* @param[in,out] root The root of the tree of Entry *nodes
* representing the information extracted from the file.
*/
virtual void parse(const char *fileName,const char *fileBuf,Entry *root) = 0;
virtual void parseInput(const char *fileName,
const char *fileBuf,
Entry *root) = 0;
/** Returns TRUE if the language identified by \a extension needs
* the C preprocessor to be run before feed the result to the input
* parser.
* @see parseInput()
*/
virtual bool needsPreprocessing(const QCString &extension) = 0;
/** Parses a source file or fragment with the goal to produce
* highlighted and cross-referenced output.
* @param[in] codeOutIntf Abstract interface for writing the result.
* @param[in] scopeName Name of scope to which the code belongs.
* @param[in] input Actual code in the form of a string
* @param[in] isExampleBlock TRUE iff the code is part of an example.
* @param[in] exampleName Name of the example.
* @param[in] fileDef File definition to which the code
* is associated.
* @param[in] startLine Starting line in case of a code fragment.
* @param[in] endLine Ending line of the code fragment.
* @param[in] inlineFragment Code fragment that is to be shown inline
* as part of the documentation.
* @param[in] memberDef Member definition to which the code
* is associated (non null in case of an inline fragment
* for a member).
*/
virtual void parseCode(CodeOutputInterface &codeOutIntf,
const char *scopeName,
const QCString &input,
bool isExampleBlock,
const char *exampleName=0,
FileDef *fileDef=0,
int startLine=-1,
int endLine=-1,
bool inlineFragment=FALSE,
MemberDef *memberDef=0
) = 0;
/** Resets the state of the code parser.
* Since multiple code fragments can together form a single example, an
* explicit function is used to reset the code parser state.
* @see parseCode()
*/
virtual void resetCodeParserState() = 0;
/** Callback function called by the comment block scanner.
* It provides a string \a text containing the prototype of a function
......@@ -60,6 +108,8 @@ class ParserInterface
virtual void handleGroupEndCommand() = 0;
};
//-----------------------------------------------------------------------------
/** \brief Manages programming language parsers.
*
* This class manages the language parsers in the system. One can
......@@ -70,13 +120,13 @@ class ParserManager
public:
/** Creates the parser manager object.
* @param defaultParser The default parser that is used when
* no explicit extension has been register for
* no explicit extension has been registered for
* a given input file.
*/
ParserManager(ParserInterface *defaultParser)
: m_defaultParser(defaultParser) {}
/** Registers a new parser.
/** Registers an additional parser.
* @param[in] extension The file extension that will trigger
* the use of this parser (e.g. ".py", or ".bas").
* @param[in] parser The parser that is to be used for the
......@@ -87,8 +137,8 @@ class ParserManager
m_parsers.insert(extension,parser);
}
/** Gets the interface to the parser associated with given \a extension,
* if there is no parser explicitly registered for the supplied extension,
/** Gets the interface to the parser associated with given \a extension.
* If there is no parser explicitly registered for the supplied extension,
* the interface to the default parser will be returned.
*/
ParserInterface *getParser(const char *extension)
......
/******************************************************************************
*
*
*
* Copyright (C) 1997-2005 by 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.
*
*/
/* This code is based on the work done by the MoxyPyDoxy team
* (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada), executed
* as part of CS179e (Compiler design project) at the UC Riverside,
* under supervision of Peter H. Fröhlic.
*/
#ifndef PYCODE_H
#define PYCODE_H
#include "qtbc.h"
#include <stdio.h>
class CodeOutputInterface;
class FileDef;
class MemberDef;
extern void parsePythonCode(CodeOutputInterface &,const char *,const QCString &,
bool ,const char *,FileDef *fd=0,
int startLine=-1,int endLine=-1,bool inlineFragment=FALSE,
MemberDef *memberDef=0);
extern void resetPythonCodeParserState();
#endif
/******************************************************************************
*
*
*
* Copyright (C) 1997-2005 by 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.
*
*/
/* This code is based on the work done by the MoxyPyDoxy team
* (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada), executed
* as part of CS179e (Compiler design project) at the UC Riverside,
* under supervision of Peter H. Fröhlic
*/
%{
#include <stdio.h>
#include <qvaluestack.h>
#include "pycode.h"
#include "message.h"
#include "scanner.h"
#include "entry.h"
#include "doxygen.h"
#include "outputlist.h"
#include "util.h"
#include "membername.h"
#include "searchindex.h"
#define YY_NEVER_INTERACTIVE 1
static ClassSDict g_codeClassSDict(17);
static QCString g_curClassName;
static QStrList g_curClassBases;
static CodeOutputInterface * g_code;
static const char * g_inputString; //!< the code fragment as text
static int g_inputPosition; //!< read offset during parsing
static const char * g_currentFontClass;
static bool g_needsTermination;
static int g_inputLines; //!< number of line in the code fragment
static int g_yyLineNr; //!< current line number
static FileDef * g_sourceFileDef;
static Definition * g_currentDefinition;
static MemberDef * g_currentMemberDef;
static bool g_includeCodeFragment;
static QCString g_realScope;
static bool g_insideBody;
static int g_bodyCurlyCount;
static bool g_searchingForBody;
static QCString g_classScope;
static int g_paramParens;
//static int g_anchorCount;
static bool g_exampleBlock;
static QCString g_exampleName;
static QCString g_exampleFile;
static QCString g_type;
static QCString g_name;
static bool g_doubleStringIsDoc;
static bool g_doubleQuote;
static int g_lastState;
static bool g_noSuiteFound;
static QValueStack<uint> g_indents; //!< Tracks indentation levels for scoping in python
static void endFontClass();
static void adjustScopesAndSuites(unsigned indentLength);
/*! Represents a stack of variable to class mappings as found in the
* code. Each scope is enclosed in pushScope() and popScope() calls.
* Variables are added by calling addVariables() and one can search
* for variable using findVariable().
*/
class PyVariableContext
{
public:
static const ClassDef *dummyContext;
class Scope : public SDict<ClassDef>
{
public:
Scope() : SDict<ClassDef>(17) {}
};
PyVariableContext()
{
m_scopes.setAutoDelete(TRUE);
}
virtual ~PyVariableContext()
{
}
void pushScope()
{
m_scopes.append(new Scope);
}
void popScope()
{
if (m_scopes.count()>0)
{
m_scopes.remove(m_scopes.count()-1);
}
}
void clear()
{
m_scopes.clear();
m_globalScope.clear();
}
void clearExceptGlobal()
{
m_scopes.clear();
}
void addVariable(const QCString &type,const QCString &name);
ClassDef *findVariable(const QCString &name);
private:
Scope m_globalScope;
QList<Scope> m_scopes;
};
void PyVariableContext::addVariable(const QCString &type,const QCString &name)
{
//printf("PyVariableContext::addVariable(%s,%s)\n",type.data(),name.data());
QCString ltype = type.simplifyWhiteSpace();
QCString lname = name.simplifyWhiteSpace();
Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast();
ClassDef *varType;
if (
(varType=g_codeClassSDict[ltype]) || // look for class definitions inside the code block
(varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions
)
{
scope->append(lname,varType); // add it to a list
}
else
{
if (m_scopes.count()>0) // for local variables add a dummy entry so the name
// is hidden to avoid FALSE links to global variables with the same name
// TODO: make this work for namespaces as well!
{
scope->append(lname,dummyContext);
}
}
}
ClassDef *PyVariableContext::findVariable(const QCString &name)
{
if (name.isEmpty()) return 0;
ClassDef *result = 0;
QListIterator<Scope> sli(m_scopes);
Scope *scope;
// search from inner to outer scope
for (sli.toLast();(scope=sli.current());--sli)
{
result = scope->find(name);
if (result)
{
return result;
}
}
// nothing found -> also try the global scope
result=m_globalScope.find(name);
return result;
}
static PyVariableContext g_theVarContext;
const ClassDef *PyVariableContext::dummyContext = (ClassDef*)0x8;
class PyCallContext
{
public:
struct Ctx
{
Ctx() : name(g_name), type(g_type), cd(0) {}
QCString name;
QCString type;
ClassDef *cd;
};
PyCallContext()
{
m_classList.append(new Ctx);
m_classList.setAutoDelete(TRUE);
}
virtual ~PyCallContext() {}
void setClass(ClassDef *cd)
{
Ctx *ctx = m_classList.getLast();
if (ctx)
{
ctx->cd=cd;
}
}
void pushScope()
{
m_classList.append(new Ctx);
}
void popScope()
{
if (m_classList.count()>1)
{
Ctx *ctx = m_classList.getLast();
if (ctx)
{
g_name = ctx->name;
g_type = ctx->type;
}
m_classList.removeLast();
}
else
{
}
}
void clear()
{
m_classList.clear();
m_classList.append(new Ctx);
}
ClassDef *getClass() const
{
Ctx *ctx = m_classList.getLast();
if (ctx)
return ctx->cd;
else
return 0;
}
private:
QList<Ctx> m_classList;
};
static PyCallContext g_theCallContext;
/*! 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;
}
static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="")
{
static bool searchEngineEnabled=Config_getBool("SEARCHENGINE");
if (searchEngineEnabled)
{
Doxygen::searchIndex->setCurrentDoc(name,base,anchor);
}
}
static void addToSearchIndex(const char *text)
{
static bool searchEngineEnabled=Config_getBool("SEARCHENGINE");
if (searchEngineEnabled)
{
Doxygen::searchIndex->addWord(text,FALSE);
}
}
static ClassDef *stripClassName(const char *s)
{
int pos=0;
QCString type = s;
QCString className;
QCString templSpec;
while (extractClassNameFromType(type,pos,className,templSpec))
{
QCString clName=className+templSpec;
ClassDef *cd=0;
if (!g_classScope.isEmpty())
{
cd=getResolvedClass(g_currentDefinition,g_sourceFileDef,g_classScope+"::"+clName);
}
if (cd==0)
{
cd=getResolvedClass(g_currentDefinition,g_sourceFileDef,clName);
}
//printf("stripClass trying `%s' = %p\n",clName.data(),cd);
if (cd)
{
return cd;
}
}
return 0;
}
/*! 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_currentFontClass) { g_code->endFontClass(); }
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=%p\n",g_yyLineNr,d);
//g_code->startLineNumber();
if (!g_includeCodeFragment && d && d->isLinkableInProject())
{
g_currentDefinition = d;
g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
g_insideBody = FALSE;
g_searchingForBody = TRUE;
g_realScope = d->name().copy();
//printf("Real scope: `%s'\n",g_realScope.data());
g_bodyCurlyCount = 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
{
g_code->writeLineNumber(d->getReference(),
d->getOutputFileBase(),
0,g_yyLineNr);
setCurrentDoc(
d->qualifiedName(),
g_sourceFileDef->getSourceFileBase(),
lineAnchor);
}
}
else
{
//g_code->codify(lineNumber);
g_code->writeLineNumber(0,0,0,g_yyLineNr);
}
//g_code->endLineNumber();
}
g_code->startCodeLine();
if (g_currentFontClass)
{
g_code->startFontClass(g_currentFontClass);
}
}
static void codify(char* text)
{
g_code->codify(text);
}
static void endCodeLine()
{
if (g_currentFontClass) { g_code->endFontClass(); }
g_code->endCodeLine();
}
/*! 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);
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);
done=TRUE;
}
}
}
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)
{
// Re-enable sometime
startCodeLine();
}
}
else
{
g_code->codify(sp);
done=TRUE;
}
}
}
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") &&
(src->isFunction() || src->isSlot())
)
{
dst->addSourceReferencedBy(src);
}
if ((Config_getBool("REFERENCES_RELATION") || Config_getBool("CALL_GRAPH")) &&
(src->isFunction() || src->isSlot())
)
{
src->addSourceReferences(dst);
}
}
static bool getLinkInScope(const QCString &c, // scope
const QCString &m, // member
const char *memberText, // exact text
CodeOutputInterface &ol,
const char *text
)
{
MemberDef *md;
ClassDef *cd;
FileDef *fd;
NamespaceDef *nd;
GroupDef *gd;
//printf("Trying `%s'::`%s'\n",c.data(),m.data());
if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef) &&
md->isLinkable())
{
//printf("Found!\n");
//Definition *d=0;
//if (cd) d=cd; else if (nd) d=nd; else if (fd) d=fd; else d=gd;
Definition *d = md->getOuterScope()==Doxygen::globalScope ?
md->getBodyDef() : md->getOuterScope();
if (md->getGroupDef()) d = md->getGroupDef();
if (d && d->isLinkable())
{
g_theCallContext.setClass(stripClassName(md->typeString()));
//printf("g_currentDefinition=%p g_currentMemberDef=%p g_insideBody=%d\n",
// g_currentDefinition,g_currentMemberDef,g_insideBody);
if (g_currentDefinition && g_currentMemberDef &&
md!=g_currentMemberDef && g_insideBody)
{
addDocCrossReference(g_currentMemberDef,md);
}
//printf("d->getReference()=`%s' d->getOutputBase()=`%s' name=`%s' member name=`%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data());
writeMultiLineCodeLink(ol,md->getReference(),
md->getOutputFileBase(),
md->anchor(),
text ? text : memberText);
addToSearchIndex(text ? text : memberText);
return TRUE;
}
}
return FALSE;
}
static bool getLink(const char *className,
const char *memberName,
CodeOutputInterface &ol,
const char *text=0)
{
QCString m=removeRedundantWhiteSpace(memberName);
QCString c=className;
if (!getLinkInScope(c,m,memberName,ol,text))
{
if (!g_curClassName.isEmpty())
{
if (!c.isEmpty()) c.prepend("::");
c.prepend(g_curClassName);
return getLinkInScope(c,m,memberName,ol,text);
}
return FALSE;
}
return TRUE;
}
/*
For a given string in the source code,
finds its class or global id and links to it.
As of June 1, '05, this ONLY finds classes
*/
static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName,
bool /*typeOnly*/=FALSE)
{
QCString className=clName;
// Don't do anything for empty text
if (className.isEmpty()) return;
ClassDef *cd=0,*lcd=0; /** Class def that we may find */
MemberDef *md=0; /** Member def that we may find */
bool isLocal=FALSE;
// printf("generateClassOrGlobalLink(className=%s)\n",className.data());
if ((lcd=g_theVarContext.findVariable(className))==0) // not a local variable
{
Definition *d = g_currentDefinition;
cd = getResolvedClass(d,g_sourceFileDef,className,&md);
//printf("d=%p g_sourceFileDef=%p\n",d,g_currentDefinition);
//printf("is found as a type %s\n",cd?cd->name().data():"<null>");
if (cd==0 && md==0) // also see if it is variable or enum or enum value
{
if (getLink(g_classScope,clName,ol,clName))
{
return;
}
}
}
else
{
if (lcd!=PyVariableContext::dummyContext)
{
g_theCallContext.setClass(lcd);
}
isLocal=TRUE;
//fprintf(stderr,"is a local variable cd=%p!\n",cd);
}
if (cd && cd->isLinkable()) // is it a linkable class
{
writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),0,clName);
addToSearchIndex(className);
if (md)
{
Definition *d = md->getOuterScope()==Doxygen::globalScope ?
md->getBodyDef() : md->getOuterScope();
if (md->getGroupDef()) d = md->getGroupDef();
if (d && d->isLinkable() && md->isLinkable() && g_currentMemberDef)
{
addDocCrossReference(g_currentMemberDef,md);
}
}
}
else // not a class, maybe a global member
{
/*
This code requires a going-over in order to
make it work for Python
//printf("class %s not linkable! cd=%p md=%p typeOnly=%d\n",clName,cd,md,typeOnly);
if (!isLocal && (md!=0 || (cd==0 && !typeOnly))) // not a class, see if it is a global enum/variable/typedef.
{
if (md==0) // not found as a typedef
{
md = setCallContextForVar(clName);
//printf("setCallContextForVar(%s) md=%p g_currentDefinition=%p\n",clName,md,g_currentDefinition);
if (md && g_currentDefinition)
{
//fprintf(stderr,"%s accessible from %s? %d md->getOuterScope=%s\n",
// md->name().data(),g_currentDefinition->name().data(),
// isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md),
// md->getOuterScope()->name().data());
}
if (md && g_currentDefinition &&
isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md)==-1)
{
md=0; // variable not accessible
}
}
if (md)
{
//printf("is a global md=%p g_currentDefinition=%s\n",md,g_currentDefinition?g_currentDefinition->name().data():"<none>");
if (md->isLinkable())
{
writeMultiLineCodeLink(ol,md->getReference(),md->getOutputFileBase(),md->anchor(),clName);
addToSearchIndex(clName);
if (g_currentMemberDef)
{
addDocCrossReference(g_currentMemberDef,md);
}
return;
}
}
}
*/
// nothing found, just write out the word
codifyLines(clName);
addToSearchIndex(clName);
}
}
/*
As of June 1, this function seems to work
for file members, but scopes are not
being correctly tracked for classes
so it doesn't work for classes yet.
*/
static void generateFunctionLink(CodeOutputInterface &ol,char *funcName)
{
//CodeClassDef *ccd=0;
ClassDef *ccd=0;
QCString locScope=g_classScope.copy();
QCString locFunc=removeRedundantWhiteSpace(funcName);
//fprintf(stdout,"*** locScope=%s locFunc=%s\n",locScope.data(),locFunc.data());
int i=locFunc.findRev("::");
if (i>0)
{
locScope=locFunc.left(i);
locFunc=locFunc.right(locFunc.length()-i-2).stripWhiteSpace();
}
//printf("generateFunctionLink(%s) classScope=`%s'\n",locFunc.data(),locScope.data());
if (!locScope.isEmpty() && (ccd=g_codeClassSDict[locScope]))
{
//printf("using classScope %s\n",g_classScope.data());
BaseClassListIterator bcli(*ccd->baseClasses());
for ( ; bcli.current() ; ++bcli)
{
if (getLink(bcli.current()->classDef->name(),locFunc,ol,funcName))
{
return;
}
}
}
if (!getLink(locScope,locFunc,ol,funcName))
{
generateClassOrGlobalLink(ol,funcName);
}
return;
}
static void startFontClass(const char *s)
{
endFontClass();
g_code->startFontClass(s);
g_currentFontClass=s;
}
static void endFontClass()
{
if (g_currentFontClass)
{
g_code->endFontClass();
g_currentFontClass=0;
}
}
#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;
}
%}
BB [ \t]+
B [ \t]*
NEWLINE \n
DIGIT [0-9]
LETTER [A-Za-z]
NONEMPTY [A-Za-z0-9_]
EXPCHAR [#(){}\[\],:.%/\\=`*~|&<>!;+-]
NONEMPTYEXP [^ \t\n:]
PARAMNONEMPTY [^ \t\n():]
IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")*
BORDER ([^A-Za-z0-9])
POUNDCOMMENT "#".*
TRISINGLEQUOTE "'''"
TRIDOUBLEQUOTE "\"\"\""
LONGSTRINGCHAR [^\\"']
ESCAPESEQ ("\\")(.)
LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ})
SMALLQUOTE ("\"\""|"\""|"'"|"''")
LONGSTRINGBLOCK ({LONGSTRINGITEM}+|{SMALLQUOTE})
SHORTSTRING ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"')
SHORTSTRINGITEM ({SHORTSTRINGCHAR}|{ESCAPESEQ})
SHORTSTRINGCHAR [^\\\n"]
STRINGLITERAL {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING})
STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR")
KEYWORD ("lambda"|"import"|"class"|"assert"|"as"|"from"|"global"|"def"|"True"|"False")
FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally")
QUOTES ("\""[^"]*"\"")
SINGLEQUOTES ("'"[^']*"'")
LONGINTEGER {INTEGER}("l"|"L")
INTEGER ({DECIMALINTEGER}|{OCTINTEGER}|{HEXINTEGER})
DECIMALINTEGER ({NONZERODIGIT}{DIGIT}*|"0")
OCTINTEGER "0"{OCTDIGIT}+
HEXINTEGER "0"("x"|"X"){HEXDIGIT}+
NONZERODIGIT [1-9]
OCTDIGIT [0-7]
HEXDIGIT ({DIGIT}|[a-f]|[A-F])
FLOATNUMBER ({POINTFLOAT}|{EXPONENTFLOAT})
POINTFLOAT ({INTPART}?{FRACTION}|{INTPART}".")
EXPONENTFLOAT ({INTPART}|{POINTFLOAT}){EXPONENT}
INTPART {DIGIT}+
FRACTION "."{DIGIT}+
EXPONENT ("e"|"E")("+"|"-")?{DIGIT}+
IMAGNUMBER ({FLOATNUMBER}|{INTPART})("j"|"J")
ATOM ({IDENTIFIER}|{LITERAL}|{ENCLOSURE})
ENCLOSURE ({PARENTH_FORM}|{LIST_DISPLAY}|{DICT_DISPLAY}|{STRING_CONVERSION})
LITERAL ({STRINGLITERAL}|{INTEGER}|{LONGINTEGER}|{FLOATNUMBER}|{IMAGNUMBER})
PARENTH_FORM "("{EXPRESSION_LIST}?")"
TEST ({AND_TEST}("or"{AND_TEST})*|{LAMBDA_FORM})
TESTLIST {TEST}( ","{TEST})*","?
LIST_DISPLAY "["{LISTMAKER}?"]"
LISTMAKER {EXPRESSION}({LIST_FOR}|(","{EXPRESSION})*","?)
LIST_ITER ({LIST_FOR}|{LIST_IF})
LIST_FOR "for"{EXPRESSION_LIST}"in"{TESTLIST}{LIST_ITER}?
LIST_IF "if"{TEST}{LIST_ITER}?
DICT_DISPLAY "\{"{KEY_DATUM_LIST}?"\}"
KEY_DATUM_LIST {KEY_DATUM}(","{KEY_DATUM})*","?
KEY_DATUM {EXPRESSION}":"{EXPRESSION}
STRING_CONVERSION "`"{EXPRESSION_LIST}"`"
PRIMARY ({ATOM}|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}|{CALL})
ATTRIBUTEREF {PRIMARY}"."{IDENTIFIER}
SUBSCRIPTION {PRIMARY}"["{EXPRESSION_LIST}"]"
SLICING ({SIMPLE_SLICING}|{EXTENDED_SLICING})
SIMPLE_SLICING {PRIMARY}"["{SHORT_SLICE}"]"
EXTENDED_SLICING {PRIMARY}"["{SLICE_LIST}"]"
SLICE_LIST {SLICE_ITEM}(","{SLICE_ITEM})*","?
SLICE_ITEM ({EXPRESSION}|{PROPER_SLICE}|{ELLIPSIS})
PROPER_SLICE ({SHORT_SLICE}|{LONG_SLICE})
SHORT_SLICE {LOWER_BOUND}?":"{UPPER_BOUND}?
LONG_SLICE {SHORT_SLICE}":"{STRIDE}?
LOWER_BOUND {EXPRESSION}
UPPER_BOUND {EXPRESSION}
STRIDE {EXPRESSION}
ELLIPSIS "..."
CALL {PRIMARY}"("({ARGUMENT_LIST}","?)?")"
ARGUMENT_LIST ({POSITIONAL_ARGUMENTS}(","{KEYWORD_ARGUMENTS})?(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|{KEYWORD_ARGUMENTS}(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|"*"{EXPRESSION}(",""**"{EXPRESSION})?|"**"{EXPRESSION})
POSITIONAL_ARGUMENTS {EXPRESSION}(","{EXPRESSION})*
KEYWORD_ARGUMENTS {KEYWORD_ITEM}(","{KEYWORD_ITEM})*
KEYWORD_ITEM {IDENTIFIER}"="{EXPRESSION}
POWER {PRIMARY}("**"{U_EXPR})?
U_EXPR ({POWER}|"-"{U_EXPR}|"+"{U_EXPR}|"\~"{U_EXPR})
M_EXPR ({U_EXPR}|{M_EXPR}"*"{U_EXPR}|{M_EXPR}"//"{U_EXPR}|{M_EXPR}"/"{U_EXPR}|{M_EXPR}"\%"{U_EXPR})
A_EXPR ({M_EXPR}|{A_EXPR}"+"{M_EXPR}|{A_EXPR}"-"{M_EXPR}
SHIFT_EXPR ({A_EXPR}|{SHIFT_EXPR}("<<"|">>"){A_EXPR})
AND_EXPR ({SHIFT_EXPR}|{AND_EXPR}"\;SPMamp;"{SHIFT_EXPR}
XOR_EXPR ({AND_EXPR}|{XOR_EXPR}"\textasciicircum"{AND_EXPR})
OR_EXPR ({XOR_EXPR}|{OR_EXPR}"|"{ XOR_EXPR})
COMPARISON {OR_EXPR}({COMP_OPERATOR}{OR_EXPR})*
COMP_OPERATOR ("<"|">"|"=="|">="|"<="|"<>"|"!="|"is""not"?|"not"?"in")
EXPRESSION ({OR_TEST}|{LAMBDA_FORM})
OR_TEST ({AND_TEST}|{OR_TEST}"or"{AND_TEST})
AND_TEST ({NOT_TEST}|{AND_TEST}"and"{NOT_TEST})
NOT_TEST ({COMPARISON}|"not"{NOT_TEST})
LAMBDA_FORM "lambda"{PARAMETER_LIST}?":"{EXPRESSION}
EXPRESSION_LIST {EXPRESSION}(","{EXPRESSION})*","?
SIMPLE_STMT ({EXPRESSION_STMT}|{ASSERT_STMT}|{ASSIGNMENT_STMT}|{AUGMENTED_ASSIGNMENT_STMT}|{PASS_STMT}|{DEL_STMT}|{PRINT_STMT}|{RETURN_STMT}|{YIELD_STMT}|{RAISE_STMT}|{BREAK_STMT}|{CONTINUE_STMT}|{IMPORT_STMT}|{GLOBAL_STMT}|{EXEC_STMT})
EXPRESSION_STMT {EXPRESSION_LIST}
ASSERT_STMT "assert"{EXPRESSION}(","{EXPRESSION})?
ASSIGNMENT_STMT ({TARGET_LIST}"=")+{EXPRESSION_LIST}
TARGET_LIST {TARGET}(","{TARGET})*","?
TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING})
%option noyywrap
%option nounput
%x Body
%x BlockWord
%x FunctionDec
%x FunctionParams
%x ClassDec
%x ClassInheritance
%x Suite
%x SuiteCaptureIndent
%x SuiteStart
%x SuiteMaintain
%x SuiteContinuing
%x LongString
%%
<Body,Suite,SuiteCaptureIndent>{
{B}{POUNDCOMMENT} {
// This eats EVERYTHING
// except the newline
startFontClass("comment");
codifyLines(yytext);
endFontClass();
}
{B}{STRINGPREFIX}?{TRIDOUBLEQUOTE}({LONGSTRINGBLOCK}?) {
// Some-what position sensitive;
// must come before NONEMPTY general
// rules.
// Eventually, we should write some intelligent
// code here to figure out if this docstring
// should be deleted.
g_doubleStringIsDoc = TRUE;
if ( g_doubleStringIsDoc )
{
g_yyLineNr+=QCString(yytext).contains('\n');
}
else
{
startFontClass("stringliteral");
codifyLines(yytext);
g_yyLineNr++;
}
g_lastState = YY_START;
g_doubleQuote = TRUE;
BEGIN( LongString );
}
{B}{STRINGPREFIX}?{TRISINGLEQUOTE}({LONGSTRINGBLOCK}?) {
//startFontClass("stringliteral");
//codifyLines(yytext);
// Eventually, we should write some intelligent
// code here to figure out if this docstring
// should be deleted.
g_doubleStringIsDoc = TRUE;
if ( g_doubleStringIsDoc )
{
g_yyLineNr+=QCString(yytext).contains('\n');
}
else
{
startFontClass("stringliteral");
codifyLines(yytext);
g_yyLineNr++;
}
g_lastState = YY_START;
g_doubleQuote = FALSE;
BEGIN( LongString );
}
}
<Body,Suite,BlockWord>{
{STRINGPREFIX}?({SINGLEQUOTES}|{QUOTES}) {
startFontClass("stringliteral");
codifyLines(yytext);
endFontClass();
}
"#".* {
startFontClass("stringliteral");
codifyLines(yytext);
endFontClass();
}
}
<LongString>{
{LONGSTRINGBLOCK} {
if ( g_doubleStringIsDoc )
{
g_yyLineNr+=QCString(yytext).contains('\n');
}
else
{
codifyLines(yytext);
}
}
{TRIDOUBLEQUOTE} {
if ( ! g_doubleStringIsDoc )
{
codify(yytext);
endFontClass();
}
if (g_doubleQuote)
{
g_doubleStringIsDoc = FALSE;
BEGIN( g_lastState );
}
}
{TRISINGLEQUOTE} {
if ( ! g_doubleStringIsDoc )
{
codify(yytext);
endFontClass();
}
if (!g_doubleQuote)
{
g_doubleStringIsDoc = FALSE;
BEGIN( g_lastState );
}
}
}
<Body,Suite>{
"def"{BB} {
startFontClass("keyword");
codify(yytext);
endFontClass();
BEGIN( FunctionDec );
}
"class"{BB} {
startFontClass("keyword");
codify(yytext);
endFontClass();
BEGIN( ClassDec );
}
}
<ClassDec>{IDENTIFIER} {
generateClassOrGlobalLink(*g_code,yytext);
// codify(yytext);
g_curClassName = yytext;
g_curClassBases.clear();
BEGIN( ClassInheritance );
}
<ClassInheritance>{
({BB}|[(,)]) {
codify(yytext);
}
{IDENTIFIER} {
// The parser
// is assuming
// that ALL identifiers
// in this state
// are base classes;
// it doesn't check to see
// that the first parenthesis
// has been seen.
// This is bad - it should
// probably be more strict
// about what to accept.
g_curClassBases.inSort(yytext);
generateClassOrGlobalLink(*g_code,yytext);
// codify(yytext);
}
":" {
codify(yytext);
// Assume this will
// be a one-line suite;
// found counter-example
// in SuiteStart.
// Push a class scope
ClassDef *classDefToAdd = new ClassDef("<code>",1,g_curClassName,ClassDef::Class,0,0,FALSE);
g_codeClassSDict.append(g_curClassName,classDefToAdd);
char *s=g_curClassBases.first();
while (s)
{
ClassDef *baseDefToAdd;
baseDefToAdd=g_codeClassSDict[s];
// Try to find class in global
// scope
if (baseDefToAdd==0)
{
baseDefToAdd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s);
}
if (baseDefToAdd && baseDefToAdd!=classDefToAdd)
{
classDefToAdd->insertBaseClass(baseDefToAdd,s,Public,Normal);
}
s=g_curClassBases.next();
}
// Reset class-parsing variables.
g_curClassName.resize(0);
g_curClassBases.clear();
g_noSuiteFound = TRUE;
BEGIN( SuiteStart );
}
}
<FunctionDec>{
{IDENTIFIER} {
generateFunctionLink(*g_code,yytext);
}
{B}"(" {
codify(yytext);
BEGIN( FunctionParams );
}
}
<FunctionParams>{
({BB}|",") {
// Parses delimiters
codify(yytext);
}
({IDENTIFIER}|{PARAMNONEMPTY}+) {
codify(yytext);
}
")" {
codify(yytext);
}
":" {
codify(yytext);
// Assume this will
// be a one-line suite;
// found counter-example
// in SuiteStart.
g_noSuiteFound = TRUE;
BEGIN( SuiteStart );
}
}
<Body,Suite>("if"|"while"|"for"|"else"|"elif") {
startFontClass("keywordflow");
codify(yytext);
endFontClass();
// printf("Entering Blockword on '%s' [%d]\n", yytext, g_yyLineNr);
}
<Body,Suite,BlockWord>{
{KEYWORD} {
// Position-sensitive rules!
// Must come AFTER keyword-triggered rules
// Must come BEFORE identifier NONEMPTY-like rules
// to syntax highlight.
startFontClass("keyword");
codify(yytext);
endFontClass();
}
{FLOWKW} {
startFontClass("keywordflow");
codify(yytext);
endFontClass();
}
}
<BlockWord>{
":" {
codify(yytext);
// printf("Requires SuiteState for BlockWord [line %d]\n", g_yyLineNr);
// Assume this will
// be a one-line suite;
// found counter-example
// in SuiteStart.
g_noSuiteFound = TRUE;
BEGIN( SuiteStart );
}
({BB}+|{NONEMPTY}+|{EXPCHAR}) { // Position-sensitive! Must come AFTER
// key-word catching rules, so that syntax
// highlighting takes priority over this.
// Match SPACE, IDENTIFIERS, or EXPchars.
codify(yytext);
}
}
<SuiteStart>{
{BB} {
codify(yytext);
}
{KEYWORD} {
startFontClass("keyword");
codifyLines(yytext);
endFontClass();
// No indentation necesary
g_noSuiteFound = FALSE;
}
{FLOWKW} {
startFontClass("keywordflow");
codifyLines(yytext);
endFontClass();
// No indentation necesary
g_noSuiteFound = FALSE;
}
({NONEMPTY}+|{EXPCHAR}+) {
codifyLines(yytext);
// No indentation necesary
g_noSuiteFound = FALSE;
}
{POUNDCOMMENT} {
// This eats EVERYTHING
// except the newline
startFontClass("comment");
codifyLines(yytext);
endFontClass();
}
{NEWLINE} {
codifyLines(yytext);
if ( g_noSuiteFound )
{
// printf("New suite to capture! [%d]\n", g_yyLineNr);
BEGIN ( SuiteCaptureIndent );
}
}
}
<SuiteCaptureIndent>{
"\n"|({BB}"\n") {
// Blankline - ignore, keep looking for indentation.
codifyLines(yytext);
}
{BB} {
// This state lasts momentarily,
// to check the indentation
// level that is about to be
// used.
codifyLines(yytext);
g_indents.push(yyleng);
// printf("Captured indent of %d [line %d]\n", yyleng, g_yyLineNr);
BEGIN( Suite );
}
}
<SuiteMaintain>{
{BB}/({NONEMPTY}|{EXPCHAR}) {
// This implements poor
// indendation-tracking;
// should be improved.
// (translate tabs to space, etc)
codifyLines(yytext);
adjustScopesAndSuites(yyleng);
}
"\n"|({BB}"\n") {
// If this ever succeeds,
// it means that this is
// a blank line, and
// can be ignored.
codifyLines(yytext);
}
""/({NONEMPTY}|{EXPCHAR}) {
// Default rule; matches
// the empty string, assuming
// real text starts here.
// Just go straight to Body.
adjustScopesAndSuites(0);
}
}
<Suite>{NEWLINE} {
codifyLines(yytext);
BEGIN( SuiteMaintain );
}
<Body,Suite>({NONEMPTY}+|{EXPCHAR}+|{BB}) {
codify(yytext);
}
<Body>{NEWLINE} {
codifyLines(yytext);
}
<*>({NONEMPTY}|{EXPCHAR}|{BB}) { // This should go one character at a time.
codify(yytext);
// printf("[pycode] '%s' [ state %d ] [line %d] no match\n",
// yytext, YY_START, g_yyLineNr);
endFontClass();
BEGIN(Body);
}
<*>{NEWLINE} {
codifyLines(yytext);
//printf("[pycode] %d NEWLINE [line %d] no match\n",
// YY_START, g_yyLineNr);
endFontClass();
BEGIN(Body);
}
<*>. {
codify(yytext);
// printf("[pycode] '%s' [ state %d ] [line %d] no match\n",
// yytext, YY_START, g_yyLineNr);
endFontClass();
BEGIN(Body);
}
%%
/*@ ----------------------------------------------------------------------------
*/
void resetPythonCodeParserState()
{
g_currentDefinition = 0;
g_currentMemberDef = 0;
g_doubleStringIsDoc = FALSE;
g_paramParens = 0;
g_indents.clear();
BEGIN( Body );
}
/*!
Examines current stack of white-space indentations;
re-syncs the parser with the correct scope.
*/
static void adjustScopesAndSuites(unsigned indentLength)
{
// States to pop
if (!g_indents.isEmpty() && indentLength < g_indents.top())
{
while (!g_indents.isEmpty() && indentLength < g_indents.top())
{
// printf("Exited scope indent of [%d]\n", g_indents.top());
g_indents.pop(); // Pop the old suite's indentation
g_currentMemberDef=0;
if (g_currentDefinition)
g_currentDefinition=g_currentDefinition->getOuterScope();
}
}
// Are there any remaining indentation levels for suites?
if (!g_indents.isEmpty())
{
BEGIN( Suite );
}
else
{
BEGIN( Body );
}
}
void parsePythonCode(CodeOutputInterface &od,const char *className,
const QCString &s,bool exBlock, const char *exName,
FileDef *fd,int startLine,int endLine,bool inlineFragment,
MemberDef *)
{
//printf("***parseCode()\n");
//--- some code to eliminate warnings---
className = "";
exBlock = FALSE;
exName = "";
inlineFragment = "";
//--------------------------------------
if (s.isEmpty()) return;
g_code = &od;
g_inputString = s;
g_inputPosition = 0;
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;
// Starts line 1 on the output
startCodeLine();
pycodeYYrestart( pycodeYYin );
pycodeYYlex();
if (!g_indents.isEmpty())
{
// printf("Exited pysourceparser in inconsistent state!\n");
}
if (g_needsTermination)
{
endFontClass();
g_code->endCodeLine();
}
return;
}
#if !defined(YY_FLEX_SUBMINOR_VERSION)
extern "C" { // some bogus code to keep the compiler happy
void pycodeYYdummy() { yy_flex_realloc(0,0); }
}
#else
#error "You seem to be using a version of flex newer than 2.5.4. These are currently incompatible with 2.5.4, and do NOT work with doxygen! Please use version 2.5.4 or expect things to be parsed wrongly! A bug report has been submitted (#732132)."
#endif
/******************************************************************************
*
*
*
* Copyright (C) 1997-2005 by 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.
*
*/
/* This code is based on the work done by the MoxyPyDoxy team
* (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada), executed
* as part of CS179e (Compiler design project) at the UC Riverside,
* under supervision of Peter H. Fröhlic.
*/
#ifndef PYSCANNER_H
#define PYSCANNER_H
#include "parserintf.h"
/** \brief Python Language parser using state-based lexical scanning.
*
* This is the Python language parser for doxygen.
*/
class PythonLanguageScanner : public ParserInterface
{
public:
void parseInput(const char * fileName,
const char *fileBuf,
Entry *root);
bool needsPreprocessing(const QCString &extension);
void parseCode(CodeOutputInterface &codeOutIntf,
const char *scopeName,
const QCString &input,
bool isExampleBlock,
const char *exampleName=0,
FileDef *fileDef=0,
int startLine=-1,
int endLine=-1,
bool inlineFragment=FALSE,
MemberDef *memberDef=0
);
void resetCodeParserState();
void parsePrototype(const char *text);
void handleGroupStartCommand(const char *header);
void handleGroupEndCommand();
};
#endif
/******************************************************************************
*
*
*
* Copyright (C) 1997-2005 by 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.
*
*/
/* This code is based on the work done by the MoxyPyDoxy team
* (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada), executed
* as part of CS179e (Compiler design project) at the UC Riverside,
* under supervision of Peter H. Fröhlic.
*/
%{
/*
* includes
*/
#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 "pyscanner.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 "pycode.h"
#define YY_NEVER_INTERACTIVE 1
/* -----------------------------------------------------------------
*
* statics
*/
static ParserInterface *g_thisParser;
static const char * inputString;
static int inputPosition;
static QFile inputFile;
static Protection protection;
static Protection baseProt;
int tabsize = 0;
static QStack<int> spaceStack;
static int sharpCount = 0 ;
static int roundCount = 0 ;
static int curlyCount = 0 ;
static int padCount = 0 ;
static QCString slString;
static Entry* current_root = 0 ;
static Entry* global_root = 0 ;
static Entry* current = 0 ;
static Entry* previous = 0 ;
static int yyLineNr = 1 ;
static int anonCount = 0 ;
static QCString yyFileName;
static MethodTypes mtype;
static bool gstat;
static Specifier virt;
static Specifier baseVirt;
static QCString msType,msName,msArgs;
static int memberGroupId = DOX_NOGROUP;
static QCString memberGroupHeader;
static QCString memberGroupDocs;
static bool isTypedef;
//static char afterDocTerminator;
static QCString sectionLabel;
static QCString sectionTitle;
//static SectionInfo::SectionType
// sectionType;
static QCString funcPtrType;
static QCString templateStr;
static QCString aliasName;
static QCString baseName;
static QCString formulaText;
static QCString formulaEnd;
static QCString fullArgString;
//static QCString *currentTemplateSpec;
static QStack<Grouping> autoGroupStack;
static Grouping lastDefGroup( "", Grouping::GROUPING_LOWEST );
static bool insideFormula;
static bool insideTryBlock=FALSE;
static bool insideCode;
static int depthIf;
static QCString memberGroupRelates;
static QCString memberGroupInside;
static QCString xrefItemKey;
static QCString xrefItemTitle;
static QCString xrefListTitle;
static QCString g_skipBlockName;
static QCString oldStyleArgType;
static QCString docBackup;
static QCString briefBackup;
static int docBlockContext;
static QCString docBlock;
static QCString docBlockName;
static bool docBlockInBody;
static bool docBlockJavaStyle;
static bool docBrief;
static bool g_doubleQuote;
static bool g_specialBlock;
int g_indent = 0;
int class_indent = 0;
int classKeywordIndent = 0;
//-----------------------------------------------------------------------------
static void initParser()
{
sectionLabel.resize(0);
sectionTitle.resize(0);
baseName.resize(0);
formulaText.resize(0);
protection = Public;
baseProt = Public;
sharpCount = 0;
roundCount = 0;
curlyCount = 0;
memberGroupId = DOX_NOGROUP;
memberGroupRelates.resize(0);
memberGroupInside.resize(0);
mtype = Method;
gstat = FALSE;
virt = Normal;
baseVirt = Normal;
isTypedef = FALSE;
autoGroupStack.clear();
insideTryBlock = FALSE;
autoGroupStack.setAutoDelete(TRUE);
lastDefGroup.groupname.resize(0);
insideFormula = FALSE;
insideCode=FALSE;
previous = 0;
}
static void initEntry()
{
//current->python = TRUE;
current->protection = protection ;
current->mtype = mtype;
current->virt = virt;
current->stat = gstat;
current->mGrpId = memberGroupId;
current->relates = memberGroupRelates.copy();
current->inside = memberGroupInside.copy();
current->objc = FALSE; //insideObjC;
current->parent = current_root;
if (!autoGroupStack.isEmpty())
{
//printf("Appending group %s\n",autoGroupStack.top()->groupname.data());
current->groups->append(new Grouping(*autoGroupStack.top()));
}
}
//-----------------------------------------------------------------------------
static void lineCount()
{
for( const char* c = yytext ; *c ; ++c )
yyLineNr += (*c == '\n') ;
}
#if 0
// Appends the current-name to current-type;
// Destroys current-name.
// Destroys current->args and current->argList
static void addType( Entry* current )
{
uint tl=current->type.length();
if ( tl>0 && !current->name.isEmpty() && current->type.at(tl-1)!='.')
{
current->type += ' ' ;
}
current->type += current->name ;
current->name.resize(0) ;
tl=current->type.length();
if ( tl>0 && !current->args.isEmpty() && current->type.at(tl-1)!='.')
{
current->type += ' ' ;
}
current->type += current->args ;
current->args.resize(0) ;
current->argList->clear();
}
static QCString stripQuotes(const char *s)
{
QCString name;
if (s==0 || *s==0) return name;
name=s;
if (name.at(0)=='"' && name.at(name.length()-1)=='"')
{
name=name.mid(1,name.length()-2);
}
return name;
}
#endif
//-----------------------------------------------------------------
static void addMemberGroupDocs()
{
memberGroupDocs=current->brief.stripWhiteSpace();
current->doc = current->doc.stripWhiteSpace();
if (!memberGroupDocs.isEmpty() && !current->doc.isEmpty())
{
memberGroupDocs+="\n\n";
}
memberGroupDocs+=current->doc;
MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(memberGroupId);
if (info)
{
info->doc = memberGroupDocs;
info->docFile = yyFileName;
}
current->doc.resize(0);
current->brief.resize(0);
}
//-----------------------------------------------------------------
static void startCommentBlock(bool brief)
{
if (brief)
{
current->briefFile = yyFileName;
current->briefLine = yyLineNr;
}
else
{
current->docFile = yyFileName;
current->docLine = yyLineNr;
}
}
/*
static void appendDocBlock() {
previous = current;
current_root->addSubEntry(current);
current = new Entry;
initEntry();
}
*/
static void handleCommentBlock(const QCString &doc,bool brief)
{
//printf("handleCommentBlock(doc=[%s] brief=%d docBlockInBody=%d\n",
// doc.data(),brief,docBlockInBody);
// TODO: Fix me
docBlockInBody=FALSE;
if (docBlockInBody && previous && !previous->doc.isEmpty())
{
previous->doc=previous->doc.stripWhiteSpace()+"\n\n";
}
if (parseCommentBlock(
g_thisParser,
(docBlockInBody && previous) ? previous : current,
doc, // text
yyFileName, // file
brief ? current->briefLine : current->docLine, // line of block start
docBlockInBody ? FALSE : brief,
FALSE, // javadoc style
protection)
) // need to start a new entry
{
// printf("adding node to nodelist...");
if (current->section==Entry::MEMBERGRP_SEC)
{
addMemberGroupDocs();
}
current_root->addSubEntry(current);
previous = current;
current = new Entry ;
initEntry();
}
}
//-----------------------------------------------------------------------------
/* ----------------------------------------------------------------- */
#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 && inputString[inputPosition] )
{
*buf = inputString[inputPosition++] ;
//printf("%d (%c)\n",*buf,*buf);
c++; buf++;
}
return c;
}
%}
/* start command character */
BB [ \t]+
B [ \t]*
NEWLINE \n
BN [ \t\n]
DIGIT [0-9]
LETTER [A-Za-z]
NONEMPTY [A-Za-z0-9_]
EXPCHAR [#(){}\[\],:.%/\\=`*~|&<>!;+-]
NONEMPTYEXP [^ \t\n:]
PARAMNONEMPTY [^ \t\n():]
IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")*
BORDER ([^A-Za-z0-9])
POUNDCOMMENT "#".*
TRISINGLEQUOTE "'''"
TRIDOUBLEQUOTE "\"\"\""
LONGSTRINGCHAR [^\\"']
ESCAPESEQ ("\\")(.)
LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ})
SMALLQUOTE ("\"\""|"\""|"'"|"''")
LONGSTRINGBLOCK ({LONGSTRINGITEM}+|{SMALLQUOTE})
SHORTSTRING ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"')
SHORTSTRINGITEM ({SHORTSTRINGCHAR}|{ESCAPESEQ})
SHORTSTRINGCHAR [^\\\n"]
STRINGLITERAL {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING})
STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR")
KEYWORD ("lambda"|"import"|"class"|"assert"|"as"|"from"|"global"|"def"|"True"|"False")
FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally")
QUOTES ("\""[^"]*"\"")
SINGLEQUOTES ("'"[^']*"'")
STARTDOCSYMS "##"
%option noyywrap
%option nounput
/* Main start state */
%x Body
/* Mid-comment states */
/* %x FuncDoubleComment */
/* %x ClassDoubleComment */
%x TryClassDocString
%x MultiDoubleComment
%x SpecialComment
/* Function states */
%x FunctionDec
%x FunctionParams
/* Class states */
%x ClassDec
%x ClassInheritance
%x ClassCaptureIndent
%%
/* ------------ Function recognition rules -------------- */
<FunctionDec>{
{IDENTIFIER} {
//found function name
if (current->type.isEmpty())
{
current->type = "def";
}
current->name = yytext;
current->name = current->name.stripWhiteSpace();
current->fileName = yyFileName;
}
{B}"(" {
BEGIN( FunctionParams );
}
}
<FunctionParams>{
({BB}|",") {
}
{IDENTIFIER} { // Name of parameter
lineCount();
Argument *a = new Argument;
current->argList->append(a);
current->argList->getLast()->name = QCString(yytext).stripWhiteSpace();
current->argList->getLast()->type = "";
}
"="[^,)\n]+ { // default value
// TODO: this rule is too simple, need to be able to
// match things like =")" as well!
QCString defVal=&yytext[1];
if (current->argList->getLast())
{
current->argList->getLast()->defval=defVal.stripWhiteSpace();
}
}
")" { // end of parameter list
}
":"{BN}* {
lineCount();
// Push the entry.
previous = current;
current_root->addSubEntry(current);
current = new Entry ;
initEntry();
BEGIN( Body );
}
{PARAMNONEMPTY} { // Default rule inside arguments.
}
}
<Body>{
"def"{BB} {
lineCount();
current->fileName = yyFileName;
current->startLine = yyLineNr;
current->bodyLine = yyLineNr;
current->section = Entry::FUNCTION_SEC;
current->protection = protection = Public;
current->objc = FALSE;
current->virt = Normal;
current->stat = FALSE;
current->mtype = mtype = Method;
current->type.resize(0);
current->name.resize(0);
current->args.resize(0);
current->argList->clear();
// If this function has slipped out
// of the parent scope, jump out.
if ( g_indent == 0 || g_indent < class_indent )
{
// printf("Function has slipped out of scope! (%d < %d)", g_indent, class_indent);
class_indent = 0;
if (current_root->parent)
{
current_root = current_root->parent;
}
else
{
// This is bad!!!
// printf("Warning: using global root because pointer to parent was lost\n");
current_root = global_root;
}
}
BEGIN( FunctionDec );
}
"class"{BB} {
lineCount() ;
current->section = Entry::CLASS_SEC;
current->argList->clear();
current->type += "class" ;
current->fileName = yyFileName;
current->startLine = yyLineNr;
current->bodyLine = yyLineNr;
// Reset scope - new class found.
// (nested classes not supported)
classKeywordIndent = g_indent;
current_root = global_root;
BEGIN( ClassDec ) ;
}
^{BB} { // This is for capturing the current indentation
// of the current line.
g_indent = yyleng;
}
[^\n] {
// This is the major default
// that should catch everything
// else in Body.
}
{NEWLINE}+ {
lineCount();
g_indent = 0;
}
}
<MultiDoubleComment>{
{TRIDOUBLEQUOTE} {
if (g_doubleQuote)
{
if (g_specialBlock)
{
handleCommentBlock(docBlock, FALSE);
}
else
{
docBlock.resize(0);
}
BEGIN(docBlockContext);
}
else
{
docBlock += yytext;
}
}
{TRISINGLEQUOTE} {
if (!g_doubleQuote)
{
if (g_specialBlock)
{
handleCommentBlock(docBlock, FALSE);
}
else
{
docBlock.resize(0);
}
BEGIN(docBlockContext);
}
else
{
docBlock += yytext;
}
}
({LONGSTRINGBLOCK}) {
lineCount();
docBlock += yytext;
}
}
<SpecialComment>{
^{B}"#"("#")* { // skip leading hashes
}
\n/{B}"#" { // continuation of the comment on the next line
docBlock+='\n';
docBrief = FALSE;
startCommentBlock(FALSE);
yyLineNr++;
}
[^#\n]+ { // any other stuff
docBlock+=yytext;
}
\n { // new line that ends the comment
handleCommentBlock(docBlock, docBrief);
yyLineNr++;
BEGIN(docBlockContext);
}
. { // anything we missed
docBlock+=*yytext;
}
}
/* ------------ Class rules -------------- */
<ClassDec>{IDENTIFIER} {
if (current->type.isEmpty())
{
current->type = "class";
}
current->section = Entry::CLASS_SEC;
current->name = yytext;
current->name = current->name.stripWhiteSpace();
current->fileName = yyFileName;
docBlockContext = YY_START;
docBlockInBody = FALSE;
docBlockJavaStyle = FALSE;
docBlock.resize(0);
// Setting indentation to 0; this totally
// totally disallows nested classes.
// This is okay for now.
class_indent = 0;
BEGIN(ClassInheritance);
}
<ClassInheritance>{
({BB}|[(,)]) {
}
":" {
//BEGIN(TryClassDocString);
BEGIN(ClassCaptureIndent);
}
{IDENTIFIER} {
current->extends->append(
new BaseInfo(yytext,Public,Normal)
);
//Has base class-do stuff
}
}
<ClassCaptureIndent>{
"\n"|({BB}"\n") {
// Blankline - ignore, keep looking for indentation.
lineCount();
}
{BB}/({NONEMPTY}|{EXPCHAR}) {
// Indentation level found!
// Pushback the class, and
// try to take over as the current root.
// Add to tree
current_root->addSubEntry(current);
if (yyleng >= classKeywordIndent)
{
// Take over the parent if this indentation
// is greater than the indentation
// of where the class started.
current->parent = current_root;
current_root = current;
previous = 0;
class_indent = yyleng;
// printf("Found indent of %d on line %d, using it.\n", class_indent, yyLineNr);
}
else
{
// Otherwise, don't push deeper;
// this class's scope never started
// properly.
previous = current;
current->endBodyLine = yyLineNr;
// printf("Found indent, but its too small (%d < %d)", yyleng, classKeywordIndent);
}
// Re-initialize current
current = new Entry ;
initEntry();
// Remember indentation level for later funcs
g_indent = yyleng;
BEGIN( Body );
}
""/({NONEMPTY}|{EXPCHAR}) {
// Default rule; this is a syntax error
// (no indentation defined by user).
class_indent = 0;
// Just pushback an empty class, and
// resume parsing the body.
previous = current;
current_root->addSubEntry(current);
current = new Entry ;
initEntry();
// printf("Failed to find indent - skipping!");
BEGIN( Body );
}
}
/* ------------ End rules -------------- */
<*>{TRIDOUBLEQUOTE}("!")? { // start of a comment block
lineCount();
docBlockContext = YY_START;
docBlockInBody = FALSE;
docBlockJavaStyle = FALSE;
docBlock.resize(0);
g_doubleQuote = TRUE;
g_specialBlock = yytext[yyleng-1]=='!';
startCommentBlock(FALSE);
BEGIN(MultiDoubleComment);
}
<*>{TRISINGLEQUOTE}("!"?) {
lineCount();
docBlockContext = YY_START;
docBlockInBody = FALSE;
docBlockJavaStyle = FALSE;
docBlock.resize(0);
g_doubleQuote = FALSE;
g_specialBlock = yytext[yyleng-1]=='!';
startCommentBlock(FALSE);
BEGIN(MultiDoubleComment);
}
<*>{STARTDOCSYMS} {
docBlockContext = YY_START;
docBlockInBody = FALSE;
docBlockJavaStyle = TRUE;
docBrief = TRUE;
docBlock.resize(0);
startCommentBlock(TRUE);
BEGIN(SpecialComment);
}
<*>({NONEMPTY}|{EXPCHAR}|{BB}) { // This should go one character at a time.
// printf("[pyscanner] '%s' [ state %d ] [line %d] no match\n",
// yytext, YY_START, yyLineNr);
}
<*>{NEWLINE} {
//printf("[pyscanner] %d NEWLINE [line %d] no match\n",
// YY_START, yyLineNr);
lineCount();
BEGIN(Body);
}
<*>. {
//printf("[pyscanner] '%s' [ state %d ] [line %d] no match\n",
// yytext, YY_START, yyLineNr);
BEGIN(Body);
}
%%
//----------------------------------------------------------------------------
static void parseCompounds(Entry *rt)
{
//printf("parseCompounds(%s)\n",rt->name.data());
EntryListIterator eli(*rt->sublist);
Entry *ce;
for (;(ce=eli.current());++eli)
{
if (!ce->program.isEmpty())
{
//printf("-- %s ---------\n%s\n---------------\n",
// ce->name.data(),ce->program.data());
// init scanner state
padCount=0;
depthIf = 0;
inputString = ce->program;
lastDefGroup.groupname.resize(0);
inputPosition = 0;
pyscanYYrestart( pyscanYYin ) ;
BEGIN( Body ) ;
current_root = ce ;
yyFileName = ce->fileName;
//setContext();
yyLineNr = ce->startLine ;
//insideObjC = ce->objc;
//printf("---> Inner block starts at line %d objC=%d\n",yyLineNr,insideObjC);
//current->reset();
if (current) delete current;
current = new Entry;
gstat = FALSE;
int ni=ce->name.findRev("::"); if (ni==-1) ni=0; else ni+=2;
// set default protection based on the compound type
if ( ce->section==Entry::CLASS_SEC ) // class
{
current->protection = protection = Public;
}
mtype = Method;
virt = Normal;
//printf("name=%s current->stat=%d gstat=%d\n",ce->name.data(),current->stat,gstat);
memberGroupId = DOX_NOGROUP;
memberGroupRelates.resize(0);
memberGroupInside.resize(0);
pyscanYYlex() ;
delete current; current=0;
ce->program.resize(0);
if (depthIf>0)
{
warn(yyFileName,yyLineNr,"Documentation block ended in the middle of a conditional section!");
}
}
parseCompounds(ce);
}
}
//----------------------------------------------------------------------------
static void parseMain(const char *fileName,const char *fileBuf,Entry *rt)
{
initParser();
inputString = fileBuf;
inputPosition = 0;
anonCount = 0;
depthIf = 0;
protection = Public;
mtype = Method;
gstat = FALSE;
virt = Normal;
current_root = rt;
global_root = rt;
inputFile.setName(fileName);
if (inputFile.open(IO_ReadOnly))
{
yyLineNr= 1 ;
yyFileName = fileName;
//setContext();
msg("Parsing file %s...\n",yyFileName.data());
current_root = rt ;
initParser();
current = new Entry;
int sec=guessSection(yyFileName);
if (sec)
{
current->name = yyFileName;
current->section = sec;
current_root->addSubEntry(current);
current = new Entry;
}
// Set the python flags
//current_root->python = TRUE;
//current->python = TRUE;
current->reset();
pyscanYYrestart( pyscanYYin );
BEGIN( Body );
pyscanYYlex();
//call ast visitor
if (depthIf>0)
{
warn(yyFileName,yyLineNr,"Documentation block ended in the middle of a conditional section!");
}
rt->program.resize(0);
delete current; current=0;
parseCompounds(rt);
inputFile.close();
}
}
//----------------------------------------------------------------------------
static void parsePrototype(const QCString &text)
{
//printf("**** parsePrototype(%s) begin\n",text.data());
const char *orgInputString;
int orgInputPosition;
YY_BUFFER_STATE orgState;
// save scanner state
orgState = YY_CURRENT_BUFFER;
yy_switch_to_buffer(yy_create_buffer(pyscanYYin, YY_BUF_SIZE));
orgInputString = inputString;
orgInputPosition = inputPosition;
// set new string
inputString = text;
inputPosition = 0;
pyscanYYrestart( pyscanYYin );
BEGIN( Body );
pyscanYYlex();
current->name = current->name.stripWhiteSpace();
if (current->section == Entry::MEMBERDOC_SEC && current->args.isEmpty())
current->section = Entry::VARIABLEDOC_SEC;
// restore original scanner state
yy_switch_to_buffer(orgState);
inputString = orgInputString;
inputPosition = orgInputPosition;
//printf("**** parsePrototype end\n");
}
//----------------------------------------------------------------------------
void PythonLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root)
{
g_thisParser = this;
::parseMain(fileName,fileBuf,root);
// May print the AST for debugging purposes
// printAST(global_root);
}
bool PythonLanguageScanner::needsPreprocessing(const QCString &)
{
return FALSE;
}
void PythonLanguageScanner::parseCode(CodeOutputInterface &codeOutIntf,
const char *scopeName,
const QCString &input,
bool isExampleBlock,
const char *exampleName,
FileDef *fileDef,
int startLine,
int endLine,
bool inlineFragment,
MemberDef *memberDef
)
{
::parsePythonCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
fileDef,startLine,endLine,inlineFragment,memberDef);
}
void PythonLanguageScanner::parsePrototype(const char *text)
{
::parsePrototype(text);
}
void PythonLanguageScanner::resetCodeParserState()
{
::resetPythonCodeParserState();
}
void PythonLanguageScanner::handleGroupStartCommand(const char * /*header*/)
{
}
void PythonLanguageScanner::handleGroupEndCommand()
{
}
//----------------------------------------------------------------------------
#if !defined(YY_FLEX_SUBMINOR_VERSION)
//----------------------------------------------------------------------------
extern "C" { // some bogus code to keep the compiler happy
void pyscannerYYdummy() { yy_flex_realloc(0,0); }
}
#endif
......@@ -21,20 +21,21 @@
#include "language.h"
#include "doxygen.h"
#include "outputgen.h"
#include "code.h"
#include "dot.h"
#include "util.h"
#include "rtfstyle.h"
#include "message.h"
#include <qfileinfo.h>
#include "parserintf.h"
#define DBG_RTF(x) m_t << x
//#define DBG_RTF(x) do {} while(0)
RTFDocVisitor::RTFDocVisitor(QTextStream &t,BaseCodeDocInterface &ci)
RTFDocVisitor::RTFDocVisitor(QTextStream &t,CodeOutputInterface &ci,
const char *langExt)
: DocVisitor(DocVisitor_RTF), m_t(t), m_ci(ci), m_insidePre(FALSE),
m_hide(FALSE), m_indentLevel(0), m_lastIsPara(FALSE)
m_hide(FALSE), m_indentLevel(0), m_lastIsPara(FALSE), m_langExt(langExt)
{
}
......@@ -322,7 +323,9 @@ void RTFDocVisitor::visit(DocVerbatim *s)
m_t << "{" << endl;
m_t << "\\par" << endl;
m_t << rtf_Style_Reset << getStyle("CodeExample");
parseCode(m_ci,s->context(),s->text().latin1(),s->isExample(),s->exampleFile());
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,s->context(),s->text().latin1(),
s->isExample(),s->exampleFile());
//m_t << "\\par" << endl;
m_t << "}" << endl;
break;
......@@ -401,7 +404,11 @@ void RTFDocVisitor::visit(DocInclude *inc)
m_t << rtf_Style_Reset << getStyle("CodeExample");
QFileInfo cfi( inc->file() );
FileDef fd( cfi.dirPath(), cfi.fileName() );
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),
inc->isExample(),
inc->exampleFile(), &fd);
m_t << "\\par" << endl;
m_t << "}" << endl;
}
......@@ -410,7 +417,10 @@ void RTFDocVisitor::visit(DocInclude *inc)
m_t << "{" << endl;
m_t << "\\par" << endl;
m_t << rtf_Style_Reset << getStyle("CodeExample");
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile());
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),inc->isExample(),
inc->exampleFile());
m_t << "\\par" << endl;
m_t << "}" << endl;
break;
......@@ -449,7 +459,12 @@ void RTFDocVisitor::visit(DocIncOperator *op)
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
if (!m_hide) parseCode(m_ci,op->context(),op->text().latin1(),op->isExample(),op->exampleFile());
if (!m_hide)
{
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,op->context(),op->text().latin1(),
op->isExample(),op->exampleFile());
}
pushEnabled();
m_hide=TRUE;
}
......
......@@ -21,16 +21,17 @@
#include "docvisitor.h"
#include <qstack.h>
#include <qcstring.h>
class QTextStream;
class BaseCodeDocInterface;
class CodeOutputInterface;
class QString;
/*! @brief Concrete visitor implementation for RTF output. */
class RTFDocVisitor : public DocVisitor
{
public:
RTFDocVisitor(QTextStream &t,BaseCodeDocInterface &ci);
RTFDocVisitor(QTextStream &t,CodeOutputInterface &ci,const char *langExt);
//--------------------------------------
// visitor functions for leaf nodes
......@@ -149,12 +150,13 @@ class RTFDocVisitor : public DocVisitor
//--------------------------------------
QTextStream &m_t;
BaseCodeDocInterface &m_ci;
CodeOutputInterface &m_ci;
bool m_insidePre;
bool m_hide;
int m_indentLevel;
QStack<bool> m_enabled;
bool m_lastIsPara;
QCString m_langExt;
};
#endif
......@@ -2483,9 +2483,9 @@ void RTFGenerator::endParamList()
t << "}";
}
void RTFGenerator::printDoc(DocNode *n)
void RTFGenerator::printDoc(DocNode *n,const char *langExt)
{
RTFDocVisitor *visitor = new RTFDocVisitor(t,*this);
RTFDocVisitor *visitor = new RTFDocVisitor(t,*this,langExt);
n->accept(visitor);
delete visitor;
}
......
......@@ -43,7 +43,7 @@ class RTFGenerator : public OutputGenerator
bool isEnabled(OutputType o) { return (o==RTF && active); }
OutputGenerator *get(OutputType o) { return (o==RTF) ? this : 0; }
void printDoc(DocNode *);
void printDoc(DocNode *,const char *);
void startFile(const char *name,const char *manName,const char *title);
void writeFooter() {}
......
......@@ -24,32 +24,30 @@
*
* This is the language parser for doxygen. It is somewhat fuzzy and
* supports C++ and various languages that are closely related to C++,
* such as C,C#,Objective-C,Java,PHP,and IDL.
* such as C, C#, Objective-C, Java, PHP, and IDL.
*/
class CLanguageScanner : public ParserInterface
{
public:
void parse(const char *fileName,const char *fileBuf,Entry *root);
void parseInput(const char *fileName,
const char *fileBuf,
Entry *root);
bool needsPreprocessing(const QCString &extension);
void parseCode(CodeOutputInterface &codeOutIntf,
const char *scopeName,
const QCString &input,
bool isExampleBlock,
const char *exampleName=0,
FileDef *fileDef=0,
int startLine=-1,
int endLine=-1,
bool inlineFragment=FALSE,
MemberDef *memberDef=0
);
void resetCodeParserState();
void parsePrototype(const char *text);
void handleGroupStartCommand(const char *header);
void handleGroupEndCommand();
};
#if 0
#include "qtbc.h"
class OutputList;
class Entry;
// Public interface provided by the language scanner
void parseMain(Entry *,const char *fileName);
// Internal callback interface for comment block scanner
void parsePrototype(const QCString &text);
void handleGroupStartCommand(const char *header);
void handleGroupEndCommand();
#endif
#endif
......@@ -41,6 +41,7 @@
#include "defargs.h"
#include "language.h"
#include "commentscan.h"
#include "code.h"
#define YY_NEVER_INTERACTIVE 1
......@@ -1843,6 +1844,42 @@ IDLATTR ("["[^\]]*"]"){BN}*
handleGroupStartCommand(current->name);
current = tmp;
initEntry();
if (yytext[1]=='/')
{
if (yytext[2]=='!' || yytext[2]=='/')
{
docBlockContext = YY_START;
docBlockInBody = FALSE;
docBlockJavaStyle = FALSE;
docBlock.resize(0);
docBlockTerm = 0;
startCommentBlock(TRUE);
BEGIN(DocLine);
}
else
{
lastCContext=YY_START;
BEGIN(SkipCxxComment);
}
}
else
{
if (yytext[2]=='!' || yytext[2]=='*')
{
docBlockContext = YY_START;
docBlockInBody = FALSE;
docBlock.resize(0);
docBlockJavaStyle = yytext[2]=='*' && Config_getBool("JAVADOC_AUTOBRIEF");
docBlockTerm = 0;
startCommentBlock(FALSE);
BEGIN(DocBlock);
}
else
{
lastCContext=YY_START;
BEGIN(SkipComment);
}
}
}
<FindMembers,FindFields,ReadInitializer>"//"([!/]?){B}*{CMD}"}".*|"/*"([!*]?){B}*{CMD}"}".*"*/" {
handleGroupEndCommand();
......@@ -4540,12 +4577,42 @@ static void handleGroupEndCommand()
//----------------------------------------------------------------------------
void CLanguageScanner::parse(const char *fileName,const char *fileBuf,Entry *root)
void CLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root)
{
g_thisParser = this;
::parseMain(fileName,fileBuf,root);
}
void CLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
const char * scopeName,
const QCString & input,
bool isExampleBlock,
const char * exampleName,
FileDef * fileDef,
int startLine,
int endLine,
bool inlineFragment,
MemberDef *memberDef
)
{
::parseCCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
fileDef,startLine,endLine,inlineFragment,memberDef);
}
bool CLanguageScanner::needsPreprocessing(const QCString &extension)
{
QCString fe=extension.lower();
return
!( fe==".java" || fe==".as" || fe==".cs" || fe==".d" || fe==".php" ||
fe==".php4" || fe==".inc" || fe==".phtml" || fe==".m" || fe==".mm"
);
}
void CLanguageScanner::resetCodeParserState()
{
::resetCCodeParserState();
}
void CLanguageScanner::parsePrototype(const char *text)
{
::parsePrototype(text);
......
......@@ -2698,6 +2698,8 @@ static QCString getCanonicalTypeForIdentifier(
symName=word;
}
//printf("symName=%s templSpec=%s\n",symName.data(),templSpec.data());
if (!symName.isEmpty() && !templSpec.isEmpty() &&
(defList=Doxygen::symbolMap->find(symName+templSpec)) &&
defList->count()==1) // word without scope but with template specs
......@@ -2733,6 +2735,10 @@ static QCString getCanonicalTypeForIdentifier(
if (cd) // known type
{
result = cd->qualifiedNameWithTemplateParameters();
if (cd->isTemplate())
{
*tSpec="";
}
}
else if (mType && mType->isEnumerate()) // an enum
{
......@@ -2799,15 +2805,15 @@ static QCString extractCanonicalType(Definition *d,FileDef *fs,const Argument *a
// then resolve any identifiers inside.
{
static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
int p=0,l,i;
int tp=0,tl,ti;
// for each identifier template specifier
while ((i=re.match(templSpec,p,&l))!=-1)
while ((ti=re.match(templSpec,tp,&tl))!=-1)
{
canType += templSpec.mid(p,i-p);
canType += getCanonicalTypeForIdentifier(d,fs,word,0);
p=i+l;
canType += templSpec.mid(tp,ti-tp);
canType += getCanonicalTypeForIdentifier(d,fs,templSpec.mid(ti,tl),0);
tp=ti+tl;
}
canType+=templSpec.right(templSpec.length()-p);
canType+=templSpec.right(templSpec.length()-tp);
}
pp=p;
......
......@@ -22,13 +22,13 @@
#include "doxygen.h"
#include "outputgen.h"
#include "xmlgen.h"
#include "code.h"
#include "dot.h"
#include "message.h"
#include "util.h"
#include <qfileinfo.h>
#include "parserintf.h"
XmlDocVisitor::XmlDocVisitor(QTextStream &t,BaseCodeDocInterface &ci)
XmlDocVisitor::XmlDocVisitor(QTextStream &t,CodeOutputInterface &ci)
: DocVisitor(DocVisitor_XML), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE)
{
}
......@@ -169,7 +169,9 @@ void XmlDocVisitor::visit(DocVerbatim *s)
{
case DocVerbatim::Code: // fall though
m_t << "<programlisting>";
parseCode(m_ci,s->context(),s->text().latin1(),s->isExample(),s->exampleFile());
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,s->context(),s->text().latin1(),
s->isExample(),s->exampleFile());
m_t << "</programlisting>";
break;
case DocVerbatim::Verbatim:
......@@ -219,13 +221,21 @@ void XmlDocVisitor::visit(DocInclude *inc)
m_t << "<programlisting>";
QFileInfo cfi( inc->file() );
FileDef fd( cfi.dirPath(), cfi.fileName() );
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),
inc->isExample(),
inc->exampleFile(), &fd);
m_t << "</programlisting>";
}
break;
case DocInclude::Include:
m_t << "<programlisting>";
parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile());
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,inc->context(),
inc->text().latin1(),
inc->isExample(),
inc->exampleFile());
m_t << "</programlisting>";
break;
case DocInclude::DontInclude:
......@@ -259,7 +269,13 @@ void XmlDocVisitor::visit(DocIncOperator *op)
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
if (!m_hide) parseCode(m_ci,op->context(),op->text().latin1(),op->isExample(),op->exampleFile());
if (!m_hide)
{
Doxygen::parserManager->getParser(m_langExt)
->parseCode(m_ci,op->context(),
op->text().latin1(),op->isExample(),
op->exampleFile());
}
pushEnabled();
m_hide=TRUE;
}
......
......@@ -21,16 +21,17 @@
#include "docvisitor.h"
#include <qstack.h>
#include <qcstring.h>
class QTextStream;
class BaseCodeDocInterface;
class CodeOutputInterface;
class QString;
/*! @brief Concrete visitor implementation for XML output. */
class XmlDocVisitor : public DocVisitor
{
public:
XmlDocVisitor(QTextStream &t,BaseCodeDocInterface &ci);
XmlDocVisitor(QTextStream &t,CodeOutputInterface &ci);
//--------------------------------------
// visitor functions for leaf nodes
......@@ -145,10 +146,11 @@ class XmlDocVisitor : public DocVisitor
//--------------------------------------
QTextStream &m_t;
BaseCodeDocInterface &m_ci;
CodeOutputInterface &m_ci;
bool m_insidePre;
bool m_hide;
QStack<bool> m_enabled;
QCString m_langExt;
};
#endif
......@@ -28,13 +28,13 @@
#include "defargs.h"
#include "outputgen.h"
#include "dot.h"
#include "code.h"
#include "pagedef.h"
#include "filename.h"
#include "version.h"
#include "xmldocvisitor.h"
#include "docparser.h"
#include "language.h"
#include "parserintf.h"
#include <qdir.h>
#include <qfile.h>
......@@ -222,7 +222,7 @@ template<class T> class ValStack
};
class XMLCodeGenerator : public BaseCodeDocInterface
class XMLCodeGenerator : public CodeOutputInterface
{
public:
......@@ -443,14 +443,15 @@ static void writeXMLDocBlock(QTextStream &t,
void writeXMLCodeBlock(QTextStream &t,FileDef *fd)
{
initParseCodeContext();
ParserInterface *pIntf=Doxygen::parserManager->getParser(fd->getDefFileExtension());
pIntf->resetCodeParserState();
XMLCodeGenerator *xmlGen = new XMLCodeGenerator(t);
parseCode(*xmlGen,
0,
fileToString(fd->absFilePath(),Config_getBool("FILTER_SOURCE_FILES")),
FALSE,
0,
fd);
pIntf->parseCode(*xmlGen,
0,
fileToString(fd->absFilePath(),Config_getBool("FILTER_SOURCE_FILES")),
FALSE,
0,
fd);
xmlGen->finish();
delete xmlGen;
}
......@@ -563,9 +564,10 @@ static void generateXMLForMember(MemberDef *md,QTextStream &ti,QTextStream &t,De
case Private: t << "private"; break;
case Package: t << "package"; break;
}
t << "\" static=\"";
if (md->isStatic()) t << "yes"; else t << "no";
t << "\"";
t << " static=\"";
if (md->isStatic()) t << "yes"; else t << "no";
t << "\"";
if (isFunc)
......@@ -573,22 +575,24 @@ static void generateXMLForMember(MemberDef *md,QTextStream &ti,QTextStream &t,De
ArgumentList *al = md->argumentList();
t << " const=\"";
if (al && al->constSpecifier) t << "yes"; else t << "no";
t << "\"";
t << "\" explicit=\"";
t << " explicit=\"";
if (md->isExplicit()) t << "yes"; else t << "no";
t << "\"";
t << "\" inline=\"";
t << " inline=\"";
if (md->isInline()) t << "yes"; else t << "no";
t << "\"";
t << "\" virt=\"";
switch (md->virtualness())
{
case Normal: t << "non-virtual"; break;
case Virtual: t << "virtual"; break;
case Pure: t << "pure-virtual"; break;
default: ASSERT(0);
}
t << " virt=\"";
switch (md->virtualness())
{
case Normal: t << "non-virtual"; break;
case Virtual: t << "virtual"; break;
case Pure: t << "pure-virtual"; break;
default: ASSERT(0);
}
t << "\"";
}
......@@ -598,15 +602,16 @@ static void generateXMLForMember(MemberDef *md,QTextStream &ti,QTextStream &t,De
//t << " volatile=\"";
//if (al && al->volatileSpecifier) t << "yes"; else t << "no";
t << "\" mutable=\"";
t << " mutable=\"";
if (md->isMutable()) t << "yes"; else t << "no";
t << "\"";
}
else if (md->memberType() == MemberDef::Property)
{
t << " readable=\"";
if (md->isReadable()) t << "yes"; else t << "no";
t << "\"";
t << "\" writable=\"";
if (md->isWritable()) t << "yes"; else t << "no";
t << "\"";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment