summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7>2005-06-15 19:21:39 (GMT)
committerdimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7>2005-06-15 19:21:39 (GMT)
commitcf0e414d83f34ebf877abbe43a15c350876669d4 (patch)
tree3f2be46d34910503ef3532aa95aa0422e86cd993
parentad65c6e23de430b2c4f0ef732b95834c87a28c20 (diff)
downloadDoxygen-cf0e414d83f34ebf877abbe43a15c350876669d4.zip
Doxygen-cf0e414d83f34ebf877abbe43a15c350876669d4.tar.gz
Doxygen-cf0e414d83f34ebf877abbe43a15c350876669d4.tar.bz2
Release-1.4.3-20050615
-rw-r--r--Doxyfile4
-rw-r--r--INSTALL4
-rw-r--r--README4
-rw-r--r--VERSION2
-rw-r--r--doc/Doxyfile2
-rw-r--r--doc/doxygen.18
-rw-r--r--doc/features.doc11
-rw-r--r--doc/htmlcmds.doc7
-rw-r--r--doc/index.doc3
-rw-r--r--doc/xmlcmds.doc90
-rw-r--r--src/Makefile.in3
-rw-r--r--src/cmdmapper.cpp91
-rw-r--r--src/cmdmapper.h127
-rw-r--r--src/code.h11
-rw-r--r--src/code.l45
-rw-r--r--src/commentcnv.l9
-rw-r--r--src/commentscan.l19
-rw-r--r--src/config.l2
-rw-r--r--src/defgen.cpp1
-rw-r--r--src/definition.cpp25
-rw-r--r--src/definition.h4
-rw-r--r--src/docparser.cpp541
-rw-r--r--src/docparser.h24
-rw-r--r--src/doctokenizer.h5
-rw-r--r--src/doctokenizer.l180
-rw-r--r--src/dot.cpp1
-rw-r--r--src/doxygen.cpp72
-rw-r--r--src/doxygen.h2
-rw-r--r--src/filedef.cpp14
-rw-r--r--src/htmldocvisitor.cpp30
-rw-r--r--src/htmldocvisitor.h12
-rw-r--r--src/htmlgen.cpp4
-rw-r--r--src/htmlgen.h2
-rw-r--r--src/index.cpp1
-rw-r--r--src/latexdocvisitor.cpp31
-rw-r--r--src/latexdocvisitor.h9
-rw-r--r--src/latexgen.cpp4
-rw-r--r--src/latexgen.h2
-rw-r--r--src/libdoxygen.pro.in4
-rw-r--r--src/libdoxygen.t6
-rw-r--r--src/mandocvisitor.cpp28
-rw-r--r--src/mandocvisitor.h8
-rw-r--r--src/mangen.cpp4
-rw-r--r--src/mangen.h2
-rw-r--r--src/memberdef.cpp6
-rw-r--r--src/membergroup.cpp1
-rw-r--r--src/outputgen.h6
-rw-r--r--src/outputlist.cpp7
-rw-r--r--src/parserintf.h62
-rw-r--r--src/pycode.h39
-rw-r--r--src/pycode.l1425
-rw-r--r--src/pyscanner.h56
-rw-r--r--src/pyscanner.l1000
-rw-r--r--src/rtfdocvisitor.cpp29
-rw-r--r--src/rtfdocvisitor.h8
-rw-r--r--src/rtfgen.cpp4
-rw-r--r--src/rtfgen.h2
-rw-r--r--src/scanner.h36
-rw-r--r--src/scanner.l69
-rw-r--r--src/util.cpp18
-rw-r--r--src/xmldocvisitor.cpp28
-rw-r--r--src/xmldocvisitor.h8
-rw-r--r--src/xmlgen.cpp53
63 files changed, 3809 insertions, 506 deletions
diff --git a/Doxyfile b/Doxyfile
index c67bf87..43ddaf8 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -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 =
diff --git a/INSTALL b/INSTALL
index 92dd978..af1b6c4 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,7 +1,7 @@
-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)
diff --git a/README b/README
index e9f0890..e9cb674 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-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)
diff --git a/VERSION b/VERSION
index cf9bc9a..c1ffc41 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.4.3-20050530
+1.4.3-20050615
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 8c0cedb..ee3eb96 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -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
diff --git a/doc/doxygen.1 b/doc/doxygen.1
index 3736aaa..fc4ccd8 100644
--- a/doc/doxygen.1
+++ b/doc/doxygen.1
@@ -1,9 +1,9 @@
.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).
diff --git a/doc/features.doc b/doc/features.doc
index 7eefca7..e3c76ad 100644
--- a/doc/features.doc
+++ b/doc/features.doc
@@ -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
diff --git a/doc/htmlcmds.doc b/doc/htmlcmds.doc
index 1639a99..0c8cd3b 100644
--- a/doc/htmlcmds.doc
+++ b/doc/htmlcmds.doc
@@ -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).
diff --git a/doc/index.doc b/doc/index.doc
index fe0cc75..6f7fa2a 100644
--- a/doc/index.doc
+++ b/doc/index.doc
@@ -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>
diff --git a/doc/xmlcmds.doc b/doc/xmlcmds.doc
new file mode 100644
index 0000000..f6440ef
--- /dev/null
+++ b/doc/xmlcmds.doc
@@ -0,0 +1,90 @@
+/******************************************************************************
+ *
+ *
+ *
+ * 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
+
+*/
+
diff --git a/src/Makefile.in b/src/Makefile.in
index 45c958c..7bc71bb 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -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:
diff --git a/src/cmdmapper.cpp b/src/cmdmapper.cpp
index 51c41eb..dddfcfd 100644
--- a/src/cmdmapper.cpp
+++ b/src/cmdmapper.cpp
@@ -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;
-//----------------------------------------------------------------------------
diff --git a/src/cmdmapper.h b/src/cmdmapper.h
index e5277f2..1c65e24 100644
--- a/src/cmdmapper.h
+++ b/src/cmdmapper.h
@@ -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;
};
diff --git a/src/code.h b/src/code.h
index 5dd0c7c..cf91b91 100644
--- a/src/code.h
+++ b/src/code.h
@@ -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
diff --git a/src/code.l b/src/code.l
index 6f2c874..598b781 100644
--- a/src/code.l
+++ b/src/code.l
@@ -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();
diff --git a/src/commentcnv.l b/src/commentcnv.l
index d1c4ad7..c29e731 100644
--- a/src/commentcnv.l
+++ b/src/commentcnv.l
@@ -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];
diff --git a/src/commentscan.l b/src/commentscan.l
index 859cc1b..9181776 100644
--- a/src/commentscan.l
+++ b/src/commentscan.l
@@ -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);
}
diff --git a/src/config.l b/src/config.l
index bfe0e13..1e49a28 100644
--- a/src/config.l
+++ b/src/config.l
@@ -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",
diff --git a/src/defgen.cpp b/src/defgen.cpp
index b2776d8..bd65ec7 100644
--- a/src/defgen.cpp
+++ b/src/defgen.cpp
@@ -28,7 +28,6 @@
#include "defargs.h"
#include "outputgen.h"
#include "dot.h"
-#include "code.h"
#include <qdir.h>
#include <qfile.h>
diff --git a/src/definition.cpp b/src/definition.cpp
index dd0fa5c..381159b 100644
--- a/src/definition.cpp
+++ b/src/definition.cpp
@@ -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();
}
diff --git a/src/definition.h b/src/definition.h
index c766652..496b368 100644
--- a/src/definition.h
+++ b/src/definition.h
@@ -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
*/
diff --git a/src/docparser.cpp b/src/docparser.cpp
index 740eba6..c5cabcd 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -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;
}
diff --git a/src/docparser.h b/src/docparser.h
index e647e84..1a58614 100644
--- a/src/docparser.h
+++ b/src/docparser.h
@@ -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;
diff --git a/src/doctokenizer.h b/src/doctokenizer.h
index e7ee442..0959b49 100644
--- a/src/doctokenizer.h
+++ b/src/doctokenizer.h
@@ -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();
diff --git a/src/doctokenizer.l b/src/doctokenizer.l
index 640c562..b2be204 100644
--- a/src/doctokenizer.l
+++ b/src/doctokenizer.l
@@ -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="";
diff --git a/src/dot.cpp b/src/dot.cpp
index 2adeeb6..7a1ec72 100644
--- a/src/dot.cpp
+++ b/src/dot.cpp
@@ -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"
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 2a073bf..d2b4303 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -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
diff --git a/src/doxygen.h b/src/doxygen.h
index d67165c..dd6ae1f 100644
--- a/src/doxygen.h
+++ b/src/doxygen.h
@@ -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();
diff --git a/src/filedef.cpp b/src/filedef.cpp
index bcc04fe..351d83b 100644
--- a/src/filedef.cpp
+++ b/src/filedef.cpp
@@ -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
);
diff --git a/src/htmldocvisitor.cpp b/src/htmldocvisitor.cpp
index 370f6a7..a560dc3 100644
--- a/src/htmldocvisitor.cpp
+++ b/src/htmldocvisitor.cpp
@@ -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;
}
diff --git a/src/htmldocvisitor.h b/src/htmldocvisitor.h
index f452ba8..d83b41f 100644
--- a/src/htmldocvisitor.h
+++ b/src/htmldocvisitor.h
@@ -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
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index 2db2aff..cae67c0 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -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;
}
diff --git a/src/htmlgen.h b/src/htmlgen.h
index f2f2364..567a166 100644
--- a/src/htmlgen.h
+++ b/src/htmlgen.h
@@ -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();
diff --git a/src/index.cpp b/src/index.cpp
index 4e78c72..10560f5 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -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"
diff --git a/src/latexdocvisitor.cpp b/src/latexdocvisitor.cpp
index 719c357..a72dd65 100644
--- a/src/latexdocvisitor.cpp
+++ b/src/latexdocvisitor.cpp
@@ -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;
}
diff --git a/src/latexdocvisitor.h b/src/latexdocvisitor.h
index 48e5b2c..fdebaf4 100644
--- a/src/latexdocvisitor.h
+++ b/src/latexdocvisitor.h
@@ -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
diff --git a/src/latexgen.cpp b/src/latexgen.cpp
index cf19c9b..7d5b79a 100644
--- a/src/latexgen.cpp
+++ b/src/latexgen.cpp
@@ -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;
}
diff --git a/src/latexgen.h b/src/latexgen.h
index 1a48b1e..2d347ea 100644
--- a/src/latexgen.h
+++ b/src/latexgen.h
@@ -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() {}
diff --git a/src/libdoxygen.pro.in b/src/libdoxygen.pro.in
index 337e920..6f6d2ab 100644
--- a/src/libdoxygen.pro.in
+++ b/src/libdoxygen.pro.in
@@ -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 \
diff --git a/src/libdoxygen.t b/src/libdoxygen.t
index 042dee2..189684e 100644
--- a/src/libdoxygen.t
+++ b/src/libdoxygen.t
@@ -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
diff --git a/src/mandocvisitor.cpp b/src/mandocvisitor.cpp
index e600709..93c5ec5 100644
--- a/src/mandocvisitor.cpp
+++ b/src/mandocvisitor.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;
}
diff --git a/src/mandocvisitor.h b/src/mandocvisitor.h
index 66fece9..aa1c54b 100644
--- a/src/mandocvisitor.h
+++ b/src/mandocvisitor.h
@@ -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
diff --git a/src/mangen.cpp b/src/mangen.cpp
index 2339208..4ef5c13 100644
--- a/src/mangen.cpp
+++ b/src/mangen.cpp
@@ -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;
diff --git a/src/mangen.h b/src/mangen.h
index 970579d..8d4d981 100644
--- a/src/mangen.h
+++ b/src/mangen.h
@@ -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);
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index ee96ff1..a18e1fc 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -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();
}
diff --git a/src/membergroup.cpp b/src/membergroup.cpp
index c2808cb..aa9e8bc 100644
--- a/src/membergroup.cpp
+++ b/src/membergroup.cpp
@@ -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"
diff --git a/src/outputgen.h b/src/outputgen.h
index c271835..1146f4d 100644
--- a/src/outputgen.h
+++ b/src/outputgen.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
diff --git a/src/outputlist.cpp b/src/outputlist.cpp
index 2dff450..b6e5e75 100644
--- a/src/outputlist.cpp
+++ b/src/outputlist.cpp
@@ -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();
}
diff --git a/src/parserintf.h b/src/parserintf.h
index 39ff310..ac81a72 100644
--- a/src/parserintf.h
+++ b/src/parserintf.h
@@ -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)
diff --git a/src/pycode.h b/src/pycode.h
new file mode 100644
index 0000000..5f2b614
--- /dev/null
+++ b/src/pycode.h
@@ -0,0 +1,39 @@
+/******************************************************************************
+ *
+ *
+ *
+ * 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
diff --git a/src/pycode.l b/src/pycode.l
new file mode 100644
index 0000000..dca57ca
--- /dev/null
+++ b/src/pycode.l
@@ -0,0 +1,1425 @@
+/******************************************************************************
+ *
+ *
+ *
+ * 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
+
diff --git a/src/pyscanner.h b/src/pyscanner.h
new file mode 100644
index 0000000..6b40ddf
--- /dev/null
+++ b/src/pyscanner.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ *
+ *
+ * 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
diff --git a/src/pyscanner.l b/src/pyscanner.l
new file mode 100644
index 0000000..f2ebb4c
--- /dev/null
+++ b/src/pyscanner.l
@@ -0,0 +1,1000 @@
+/******************************************************************************
+ *
+ *
+ *
+ * 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
+
diff --git a/src/rtfdocvisitor.cpp b/src/rtfdocvisitor.cpp
index e524800..85a020e 100644
--- a/src/rtfdocvisitor.cpp
+++ b/src/rtfdocvisitor.cpp
@@ -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;
}
diff --git a/src/rtfdocvisitor.h b/src/rtfdocvisitor.h
index 9508972..90175e3 100644
--- a/src/rtfdocvisitor.h
+++ b/src/rtfdocvisitor.h
@@ -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
diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp
index 47193ba..2f768ad 100644
--- a/src/rtfgen.cpp
+++ b/src/rtfgen.cpp
@@ -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;
}
diff --git a/src/rtfgen.h b/src/rtfgen.h
index 0495da7..d17cad8 100644
--- a/src/rtfgen.h
+++ b/src/rtfgen.h
@@ -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() {}
diff --git a/src/scanner.h b/src/scanner.h
index 2dbbf4e..8432f6f 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -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
diff --git a/src/scanner.l b/src/scanner.l
index b93df38..ddd839b 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -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);
diff --git a/src/util.cpp b/src/util.cpp
index 6728c56..679e0d3 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -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;
diff --git a/src/xmldocvisitor.cpp b/src/xmldocvisitor.cpp
index 6ff9ac1..01e5a06 100644
--- a/src/xmldocvisitor.cpp
+++ b/src/xmldocvisitor.cpp
@@ -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;
}
diff --git a/src/xmldocvisitor.h b/src/xmldocvisitor.h
index 4d77a3b..60e0820 100644
--- a/src/xmldocvisitor.h
+++ b/src/xmldocvisitor.h
@@ -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
diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp
index 8be6b44..63a5f44 100644
--- a/src/xmlgen.cpp
+++ b/src/xmlgen.cpp
@@ -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 << "\"";