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; } static int undocumented;
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:
0f99de2001-02-02Johan Sundström //! Doc for the class
cce6072001-01-10Johan Sundström class CheeseMaker {
0f99de2001-02-02Johan Sundström  //! You can even document inherits!
cce6072001-01-10Johan Sundström  inherit Earth : earth;
0f99de2001-02-02Johan Sundström  //! Doc for CheeseMaker->a()
cce6072001-01-10Johan Sundström  int a() { ... } void create(string s) { ... } } 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: class a() {
0f99de2001-02-02Johan Sundström  //! @decl foo //! ... doc for foo ...
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 ... }