cce6072001-01-10Johan Sundström  +-----------------------+ | Pike autodoc inlining | +-----------------------+ The autodoc extractor works either in C mode or in Pike mode. The reason why the two modes are not the same is that they perform two very different tasks. The C mode only has to find comments in the file, and ignores the surrounding code totally. The Pike mode, on the other hand, is supposed to be smarter and distill a lot of information from the Pike code that surrounds the comments. Both work at the file level. That makes it easy to use for example "make" to generate documentation for the source tree. Another benefit is that the generation will not have to reparse all of the tree if only one source file is changed. For Pike module trees, the extractor can recurse through the file tree on its own, but for C files, where the directory structure gives insufficient cues about what is what, there must be make targets set up manually. All generated XML files can then be merged together into the final Pike namespace. ====================================================================== a) C files ---------------------------------------------------------------------- In C files, the doc comments look like: /*! yadda yadda *! yadda yadda yadda */ Note that only lines that start with *! count, so above are only two doc lines. Any whitespace before the leading *! is skipped, so that the lines can be indented freely. In the C files, no parsing of the surrounding code is done. The context lies completely in the doc comments themselves, and the target of the doc comment is determined by special meta keywords that are not really part of the doc blocks, but rather modifiers that tell which Pike entity the doc is about. /*! @module Foo *! ... doc for the Foo module ... *! ... */ /*! @decl int a() *! ... doc for the method Foo.a() ... *! .... */ /*! @class Bar *! ... doc for the class Foo.Bar ... *! ... */ /*! @decl mapping(string:string) userprefs() *! ... doc for the method Foo.Bar->userprefs() ... *! ... */ /*! @decl int a *! @decl int b *! ... doc for the variables Foo.Bar->a and Foo.Bar->b ... *! ... */ /*! @endclass */ /*! @endmodule */ The @module and @class too keywords are to work like segment directives in assembler source files. That is, you can have "@module foo" in several C files, if the module source is spread over multiple files. However, if you write doc for the module itself in several places, an error will be triggered. ====================================================================== b) Pike files ---------------------------------------------------------------------- Doc comments look like:
0f99de2001-02-02Johan Sundström  //! yadda yadda yadda //! yadda yadda
cce6072001-01-10Johan Sundström  To be considered one doc block, the comments must be separated only by whitespace and _one_ "\n", that is they have to be on adjacent lines in the code. Each doc block in the Pike code has one or more targets; the Pike entities (modules, classes, variables etc.) that the doc block is documenting. The target of a doc comment is the coherent block of declarations adjacent to (immediately before or after) it in the code, without intervening blank lines. Examples:
0f99de2001-02-02Johan Sundström  //! Doc for alpha
cce6072001-01-10Johan Sundström  int alpha() { return 4711; }
cde4092008-06-28Martin Nilsson  protected int undocumented;
cce6072001-01-10Johan Sundström 
0f99de2001-02-02Johan Sundström  //! Error! This doc block has no destination!
cce6072001-01-10Johan Sundström  int beta;
0f99de2001-02-02Johan Sundström  //! Doc for beta
cce6072001-01-10Johan Sundström 
0f99de2001-02-02Johan Sundström  //! Doc for gamma, delta, and epsilon
cce6072001-01-10Johan Sundström  int gamma, delta; float epsilon;
0f99de2001-02-02Johan Sundström  //! Error here!
cce6072001-01-10Johan Sundström  int zeta;
0f99de2001-02-02Johan Sundström  //! ambiguous which doc to associate with zeta.
cce6072001-01-10Johan Sundström  int eta;
0f99de2001-02-02Johan Sundström  //! Error here too! ambiguous which variable is documented.
cce6072001-01-10Johan Sundström  int theta;
0f99de2001-02-02Johan Sundström  //! Doc for two methods. This is so UGLY! We strongly recommend //! using the decl keywords instead to accomplish this effect.
cce6072001-01-10Johan Sundström  int methodOne() { ... } int methodTwo() { ... }
0f99de2001-02-02Johan Sundström  //! However, it can be useful sometimes, for really short methods:
cce6072001-01-10Johan Sundström  int very_short() { return 4711; } int even_shorter() { return 0; } In Pike files, you can not use @class or @module to tell which module or class you are in. To document a class, you simply write:
3b92c22001-08-06David Norlin  //! Doc for the class class CheeseMaker
cce6072001-01-10Johan Sundström  {
3b92c22001-08-06David Norlin  //! You can even document inherits! inherit Earth : earth; //! Doc for CheeseMaker->a() int a() { ... } void create(string s) { ... }
cce6072001-01-10Johan Sundström  } The parser will automatically identify a() as a member method of the class CheeseMaker, and will detect that Earth is inherited by CheeseMaker. If a class has no documentation comment, it's internals will not be examined, thus it is an error if a class contains documentation comments but is itself undocumented:
3b92c22001-08-06David Norlin  class a() { //! @decl foo //! ... doc for foo ... } A special inlining case is that of functions and classes. When documenting these, the doc comment can be put between the head of the function/class, and the opening "{", like this: class Roy //! Documentation for Roy { .... } int un_randomize(int x) //! This function takes a random number, and transforms it into //! a predictable number. { return x = 4711; }
cce6072001-01-10Johan Sundström  If a doc block is the first in a file, and it has no target, then it is treated as doc for the file (or rather: the module/class that the file compiles into) itself. In any other case it is an error to have a targetless doc block. A target can also be set with the @decl meta keyword. If a doc comment begins with some @decl keywords, these @decl's act just like real declarations standing next to the doc. Thus:
0f99de2001-02-02Johan Sundström  //! @decl int a(int x) //! @decl int b(int x) //! Here is some doc for these functions....
cce6072001-01-10Johan Sundström  is autodocwise equivalent to:
0f99de2001-02-02Johan Sundström  //! Here is some doc for these functions....
cce6072001-01-10Johan Sundström  int a(int x) { ..... } int b(int x) { ..... } In _one_ case it is legal to have both an adjacent declaration and the @decl keyword at the block beginning. That is when you document "polymorph" methods. Then the adjacent declaration must be a method, and all @decl's must be methods that have the same name as the real method:
0f99de2001-02-02Johan Sundström  //! @decl float cube(float x) //! @decl int cube(int x) //! Gives x**3. //! @param x //! The number to cube.
cce6072001-01-10Johan Sundström  int|float cube(int|float x) { .... } The real method prototype is discarded in favour to the @decl'ed variants, who will be shown in the documentation instead. One problem that is unsolved so far is how to handle #if .. #else .. #endif constructions. The approach so far has been to ignore preprocessor directives totally. For example, the parser does not handle: #ifdef MALE int bertil() #else int berit() #endif { ... body ... }
bef6ef2001-08-09David Norlin  It a portion of the code is unextractable because it contains too much preprocessor macros and stuff, you can make the extractor skip it by using @ignore: //! @ignore HERE_ARE_SOME_STRANGE_THINGS #ifdef A A #endif //! @endignore All @ignore-@endignore sections of the file are removed before any extraction is done, so they can cross class boundaries and the like. You can nest @ignore inside eachother. Another application for @ignore is to hide actual class boundaries from the extractor: //! @ignore class C { //! @endignore //! To the parser, this function appears to be on the top level int f() { ... } //! @ignore } //! @endignore