www.digitalmars.com         C & C++   DMDScript  

D - Updated Doxygen: D support

reply Hauke Duden <H.NS.Duden gmx.net> writes:
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

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
Jan 02 2004
parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

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 ;)
Jan 02 2004
next sibling parent "Matthew" <matthew.hat stlsoft.dot.org> writes:
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

         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: ... { ... }

             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 !=

                         {
                             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;
         }
     }
 }

Jan 02 2004
prev sibling parent Hauke Duden <H.NS.Duden gmx.net> writes:
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
Jan 03 2004