| |
| Posted by J C Calvarese in reply to Hauke Duden | PermalinkReply |
|
J C Calvarese
Posted in reply to Hauke Duden
| Hauke Duden wrote:
> Stewart Gordon wrote:
>
>> I briefly tried Doxygen the other day. I soon noticed that it was omitting quite large chunks of my code from the documentation.
>>
>> Obviously version 1.3.7 doesn't by itself support D after all, and so it's trying to parse my code as if it's C++. Hence it's missing stuff like attribute blocks and the fact that class/union/struct/enum definitions aren't semicolon-terminated in D.
>>
>> Has anyone actually coded up the tweak to make Doxygen understand D? Or are the D projects that use Doxygen built around Doxygen's limitations?
>
>
> Doxygen 1.3.7 only has basic support for D. It basically treats D as a variant of C++ with a little Java and C# mixed in (this allows it to recognize interfaces, for example).
>
> To get good results you need to combine it with a filtering program that translates most of the remaining D syntax quirks into something more C++-ish. The program is called dfilter.d and it was posted in this newsgroup a while back. Make sure you get the modified version for the new Doxygen, which was posted sometime at the end of the last year. I can repost it when I get home (don't have it here at work).
>
> Hauke
I think I found your earlier message (I'm sure you'll correct me if I'm mistaken): http://www.digitalmars.com/drn-bin/wwwnews?D/20989
And here's the attached code...
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;
}
}
}
--
Justin (a/k/a jcc7)
http://jcc_7.tripod.com/d/
|