Thread overview
Updated Doxygen: D support
Jan 02, 2004
Hauke Duden
Jan 02, 2004
Hauke Duden
Jan 03, 2004
Matthew
Jan 03, 2004
Hauke Duden
January 02, 2004
I have done some hacking on doxygen to add support for D.

The advantange to the old dfilter.exe is that now D constructs that do not exist in C++ are documented better (most importantly: interfaces are interfaces, not classes).

There are still some things missing, like support for the /+ +/ comments and unittests,preconditions,postconditions...

Maybe this should be combined with an updated dfilter that does a little LESS filtering, to get the best of both worlds.

I have attached the patch file for doxygen's scanner.l file (diffed to doxygen 1.3.5).

Hauke


January 02, 2004
Hauke Duden wrote:
> I have done some hacking on doxygen to add support for D.
> 
> The advantange to the old dfilter.exe is that now D constructs that do not exist in C++ are documented better (most importantly: interfaces are interfaces, not classes).
> 
> There are still some things missing, like support for the /+ +/ comments and unittests,preconditions,postconditions...
> 
> Maybe this should be combined with an updated dfilter that does a little LESS filtering, to get the best of both worlds.

I've updated dfilter.d as suggested above (I also had to make some changes so that it compiles with the most recent version of DMD). Combined with the doxygen patch this creates pretty good documentation support.

The source file is attached.

Hauke

P.S.: Because of their size I don't want to post the binaries (dfilter.exe and doxygen.exe) in this newsgroup. If anyone wants them just send me an email...

P.P.S.: I have emailed Dimitri van Heesch and he has replied that the patch will probably be included in the official Doxygen distribution. I see good times for D docs ;)


January 03, 2004
Any chance of you posting / emailing me the original file, as I've lost my original, and I'm keen to merge your changes with mine?

Cheers

The Yuletide Log

"Hauke Duden" <H.NS.Duden@gmx.net> wrote in message news:bt4flf$bqt$1@digitaldaemon.com...
> Hauke Duden wrote:
> > I have done some hacking on doxygen to add support for D.
> >
> > The advantange to the old dfilter.exe is that now D constructs that do not exist in C++ are documented better (most importantly: interfaces are interfaces, not classes).
> >
> > There are still some things missing, like support for the /+ +/ comments and unittests,preconditions,postconditions...
> >
> > Maybe this should be combined with an updated dfilter that does a little LESS filtering, to get the best of both worlds.
>
> I've updated dfilter.d as suggested above (I also had to make some changes so that it compiles with the most recent version of DMD). Combined with the doxygen patch this creates pretty good documentation support.
>
> The source file is attached.
>
> Hauke
>
> P.S.: Because of their size I don't want to post the binaries (dfilter.exe and doxygen.exe) in this newsgroup. If anyone wants them just send me an email...
>
> P.P.S.: I have emailed Dimitri van Heesch and he has replied that the patch will probably be included in the official Doxygen distribution. I see good times for D docs ;)
>


----------------------------------------------------------------------------
----


> import std.file, std.ctype, std.c.stdio;
>
> char [] data; /* Data. */
> char *c; /* Current point. */
> char *s; /* Previous filter point. */
> char *e; /* End of the data. */
> char *p; /* Start of this token. */
>
> /* Read in a token. */
> char [] token ()
> {
> restart:
>     p = c;
>
>     if (c >= e)
>         return null;
>
>     if (isalpha (*c) || *c == '_')
>     {
>         for (c ++; c < e; c ++)
>             if (!isalnum (*c) && *c != '_')
>                 break;
>
>         return p [0 .. (int) (c - p)];
>     }
>
>     if (*c == ' ' || *c == '\r' || *c == '\n' || *c == '\t')
>     {
>         c ++;
>         goto restart;
>     }
>
>     if (*c == '"')
>     {
>         for (c ++; c < e; c ++)
>             if (*c == '\\')
>                 c ++;
>             else if (*c == '"')
>             {
>                 c ++;
>                 break;
>             }
>         goto restart;
>     }
>
>     if (*c == '\'')
>     {
>         for (c ++; c < e; c ++)
>             if (*c == '\'')
>             {
>                 c ++;
>                 break;
>             }
>         goto restart;
>     }
>
>     if (c < e - 1)
>     {
>         if (*c == '/' && c [1] == '/')
>         {
>             for (c += 2; ; c ++)
>                 if (c >= e || *c == '\n')
>                 {
>                     c ++;
>                     goto restart;
>                 }
>         }
>
>         if (*c == '/' && c [1] == '*')
>         {
>             for (c += 2; ; c ++)
>                 if (c >= e - 1 || (*c == '*' && c [1] == '/'))
>                 {
>                     c += 2;
>                     goto restart;
>                 }
>         }
>
>         if (*c == '/' && c [1] == '+')
>         {
>             int depth = 1;
>
>             for (c += 2; ; c ++)
>                 if (c >= e - 1)
>                     goto restart;
>                 else if (*c == '/' && c [1] == '+')
>                 {
>                     c += 2;
>                     depth ++;
>                 }
>                 else if (*c == '+' && c [1] == '/')
>                 {
>                     c += 2;
>                     depth --;
>                     if (!depth)
>                         goto restart;
>                 }
>         }
>     }
>
>     c ++;
>     return p [0 .. 1];
> }
>
> /* Print all text to this point and set s to the current point. */
> void flush (char *p)
> {
>     fwrite (s, (int) (p - s), 1, stdout);
>     s = c;
> }
>
> /* Consume a "{ ... }" or "(xxx) { ... }" block. */
> void skipBlock (char *p)
> {
>     char *o = s;
>
>     flush (p);
>
>     int depth = 0;
>     char [] t = token ();
>
>     if (t == "(")
>     {
>         while (1)
>         {
>             t = token ();
>             if (t == ")" || t == null)
>                 break;
>         }
>         t = token ();
>     }
>
>     if (t != "{")
>     {
>         s = p;
>         flush (c);
>         return;
>     }
>
>     while (1)
>     {
>         if (t == null)
>             break;
>         if (t == "{")
>             depth ++;
>         if (t == "}")
>         {
>             depth --;
>             if (depth == 0)
>                 break;
>         }
>
>         t = token ();
>     }
>
>     s = c;
> }
>
> int main (char [] [] args)
> {
>     if (args.length == 1)
>     {
>         printf ("%.*s FILENAME\n\nPreprocesses the file in preparation for
Doxygen.\n", args [0]);
>         return 1;
>     }
>
>     data = (char []) read (args [1]);
>     c = s = data;
>     e = s + data.length;
>
>     char [] t;
>     char [] [] protectRecord;
>     char [] protect = "public";
>     char [] [] brackets;
>     char [] nextOpenBracket;
>     char [] nextSemiColon;
>     bit insideBrackets;
>
>     while (1)
>     {
>         t = token ();
>         if (t == null)
>         {
>             flush (c);
>             return 0;
>         }
>
>         switch (t)
>         {
>             /* Remove these keywords. */
>             case "body":
>                 flush (p);
>                 s = c;
>                 break;
>
>             /* Remove these blocks. */
>             case "unittest":
>             case "invariant":
>             case "in":
>             case "out":
>                 skipBlock (p);
>                 break;
>
>             /* Remove "keyword:" but only if it is followed with a colon.
*/
>             case "override":
>             case "abstract":
>             case "final":
>                 flush (p);
>                 if ((t = token ()) == ":")
>                     s = c;
>                 break;
>
>             case ";":
>                 flush (c);
>                 printf ("%.*s", nextSemiColon);
>                 nextSemiColon = null;
>                 break;
>
>             /* "keyword" without "keyword:" into "keyword: ... { ... }
antikeyword:" */
>             case "public":
>             case "private":
>             case "protected":
>                 flush (p);
>                 if (token () == ":")
>                 {
>                     printf ("%.*s", t);
>                     protect = t;
>                     break;
>                 }
>
>                 if (t != protect)
>                 {
>                     printf ("%.*s: ", t);
>                     s = p;
>                     nextOpenBracket = protect ~ ":";
>                     nextSemiColon = protect ~ ":";
>                 }
>                 break;
>
>             /* Modify into "package". */
>             /*Not necessary anymore
> case "module":
>                 flush (p);
>                 printf ("package ", nextSemiColon);
>                 s = c;
>                 break;*/
>
>             /* Modify into import X.Y.*. */
> /* Not necessary anymore
>             case "import":
>                 flush (p);
>                 printf ("import ", nextSemiColon);
>
>                 while ((t = token ()) != null)
>                 {
>                     if (t == ";")
>                     {
>                         printf (";");
>                         break;
>                     }
>                     else
>                         printf ("%.*s", t);
>                 }
>                 s = c;
>                 break;*/
>
>             /* Remove "extern (...)". */
>             case "extern":
>                 flush (p);
>                 if ((t = token ()) != "(")
>                 {
>                     c = p;
>                     break;
>                 }
>
>                 while ((t = token ()) != null)
>                     if (t == ")")
>                         break;
>                 s = c;
>                 break;
>
>             /* "alias" into "typedef". */
>             case "alias":
>                 flush (p);
>                 printf ("typedef");
>                 s = c;
>                 break;
>
>             /* "instance" into "typedef". */
>             case "instance":
>                 flush (p);
>                 printf ("typedef");
>                 s = c;
>
>                 while ((t = token ()) != null)
>                     if (t == "(")
>                     {
>                         flush (p);
>                         printf ("<");
>                         s = c;
>                     }
>                     else if (t == ")")
>                     {
>                         flush (p);
>                         printf (">");
>                         s = c;
>                         break;
>                     }
>
>                 break;
>
>             case "{":
>                 brackets ~= nextOpenBracket;
>                 nextOpenBracket = null;
>                 break;
>
>             /* "}" into "};" */
>             case "}":
>                 if (protectRecord.length)
>                 {
>                     protect = protectRecord [protectRecord.length - 1];
>                     protectRecord.length = protectRecord.length - 1;
>                 }
>
>                 flush (c);
>                 printf (";");
>                 if (brackets.length && brackets [brackets.length - 1])
>                 {
>                     printf (" %.*s", brackets [brackets.length - 1]);
>                     brackets = brackets [0 .. brackets.length - 1];
>                 }
>                 break;
>
>             /* "class ... {" into "class ... { public:". */
>             /* Not necessary anymore
> case "class":
>             case "interface":
>             {
>                 bit colon = false;
>
>                 flush (p);
>
> printf ("class");
>
> protectRecord ~= protect;
> protect = "public";
>
>                 while ((t = token ()) != null)
>                 {
>                 restart:
>                     if (t == ":" && !colon)
>                     {
>                         colon = true;
>                         t = token ();
>                         if (t != "public" && t != "private" && t !=
"protected")
>                         {
>                             flush (p);
>                             s = p;
>                             printf ("public ");
>                             goto restart;
>                         }
>                     }
>                     else if (t == ";")
>                         break;
>                     else if (t == "{")
>                     {
>                         flush (c);
> printf (" public:");
>                         break;
>                     }
>                 }
>                 break;
>             }*/
>
>             /* "template name (x)" into "template namespace name <x>". */
>             case "template":
>                 protectRecord ~= protect;
>                 protect = "public";
>
>                 flush (c);
>                 printf (" class");
>                 while ((t = token ()) != null)
>                     if (t == "(")
>                     {
>                         flush (p);
>                         printf ("<");
>                         s = c;
>                     }
>                     else if (t == ")")
>                     {
>                         flush (p);
>                         printf (">");
>                         s = c;
>                         break;
>                     }
>
>                 while ((t = token ()) != null)
>                     if (t == "{")
>                     {
>                         flush (c);
>                         printf (" public:");
>                         break;
>                     }
>                     else if (t == ";")
>                         break;
>                 break;
>
>             /* "delegate (...) name" into "(*name) (...)". */
>             case "delegate":
>                 flush (p);
>                 s = c;
>                 while ((t = token ()) != null)
>                     if (t == ")")
>                     {
>                         t = token ();
>                         printf ("(*%.*s)", t);
>                         flush (p);
>                         s = c;
>                         break;
>                     }
>                 break;
>
>             default:
>                 break;
>         }
>     }
> }
>



January 03, 2004
Yaneurao (another D-fan from Japan) was kind enough to put a ZIP file on his web site that contains the Doxygen and dfilter binaries, as well as the dfilter source code.

Here's a link:

http://www.sun-inet.or.jp/~yaneurao/dlang/lib/ddoc.zip



Hauke