From e8d70b1b4abe17f1425aa7b8d4e582cd02372766 Mon Sep 17 00:00:00 2001
From: Mark Wooding <mdw@distorted.org.uk>
Date: Sat, 3 Aug 2019 21:12:31 +0100
Subject: [PATCH] doc/: Reorder the arguments to `\descref'.

We now have

	\descref*{CAT}{NAME}[TEXT]

rather than

	\descref*{NAME}[TEXT]{CAT}

which flows much better.  There's a complication, that `\@ifnextchar'
gobbles space while looking for its character: implement a custom
version which doesn't do that.

The call sites were mostly fixed by [long line]

	$ sed -i '/\\descref\(\*\)\?\({[^}]\+}\(\[[^]]\+]\)\?\)\({[^}]\+}\)/ s//\\descref\1\4\2/g' doc/*.tex

but some calls run over two lines and had to be found and fixed by hand.
---
 doc/clang.tex    | 42 +++++++++++++++++++++---------------------
 doc/concepts.tex | 22 +++++++++++-----------
 doc/misc.tex     |  8 ++++----
 doc/runtime.tex  | 56 ++++++++++++++++++++++++++++----------------------------
 doc/sod.sty      | 21 ++++++++++++++-------
 doc/syntax.tex   |  8 ++++----
 6 files changed, 82 insertions(+), 75 deletions(-)

diff --git a/doc/clang.tex b/doc/clang.tex
index b572fe4..92c822b 100644
--- a/doc/clang.tex
+++ b/doc/clang.tex
@@ -68,11 +68,11 @@ specified to return interned objects: programs may rely on receiving the same
 not specified, clients may still not rely on receiving fresh objects.
 
 A convenient S-expression notation is provided by the
-\descref{c-type}[macro]{mac}.  Use of this macro is merely an abbreviation
+\descref{mac}{c-type}[macro].  Use of this macro is merely an abbreviation
 for corresponding use of the various constructor functions, and therefore
 interns type objects in the same manner.  The syntax accepted by the macro
-can be extended in order to support new classes: see \descref{defctype}{mac},
-\descref{c-type-alias}{mac} and \descref{define-c-type-syntax}{mac}.
+can be extended in order to support new classes: see \descref{mac}{defctype},
+\descref{mac}{c-type-alias} and \descref{mac}{define-c-type-syntax}.
 
 The descriptions of each of the various classes include descriptions of the
 initargs which may be passed to @|make-instance| when constructing a new
@@ -83,9 +83,9 @@ syntax are strongly recommended over direct use of @|make-instance|.
 There are two protocols for printing C types.  Unfortunately they have
 similar names.
 \begin{itemize}
-\item The \descref{print-c-type}[function]{gf} prints a C type value using
+\item The \descref{gf}{print-c-type}[function] prints a C type value using
   the S-expression notation.  It is mainly useful for diagnostic purposes.
-\item The \descref{pprint-c-type}[function]{gf} prints a C type as a
+\item The \descref{gf}{pprint-c-type}[function] prints a C type as a
   C-syntax declaration.
 \end{itemize}
 Neither generic function defines a default primary method; subclasses of
@@ -169,7 +169,7 @@ type specifier.  Type specifiers fit into two syntactic categories.
 \begin{describe}{gf}{expand-c-type-spec @<type-spec> @> @<form>}
   Returns the Lisp form that @|(c-type @<type-spec>)| would expand into.
 
-  If @<type-spec> is a list, then \descref{expand-c-type-form}{gf} is
+  If @<type-spec> is a list, then \descref{gf}{expand-c-type-form} is
   invoked.
 \end{describe}
 
@@ -258,14 +258,14 @@ argument lists for methods.  This is done by @|c-type-equal-p|.
   directly attached.  If the @<kernel> function intends to provide its own
   additional declarator operators, it should check the @<priority> in order
   to determine whether parentheses are necessary.  See also the
-  \descref{maybe-in-parens}[macro]{mac}.
+  \descref{mac}{maybe-in-parens}[macro].
 
   The @<spacep> argument indicates whether a space needs to be printed in
   order to separate the declarator from the declaration specifiers.  A kernel
   which contains an identifier should insert a space before the identifier
   when @<spacep> is non-nil.  An `empty' kernel, as found in an abstract
   declarator (one that specifies no name), looks more pleasing without a
-  trailing space.  See also the \descref{c-type-space}[function]{fun}.
+  trailing space.  See also the \descref{fun}{c-type-space}[function].
 
   Every concrete subclass of @|c-type| is expected to provide a primary
   method on this function.  There is no default primary method.
@@ -329,7 +329,7 @@ is shown in \xref{tab:clang.ctypes.qual}.
 
 The default behaviour, on output, is to convert keywords to lowercase and
 hope for the best: special cases can be dealt with by adding appropriate
-methods to \descref{c-qualifier-keyword}{gf}.
+methods to \descref{gf}{c-qualifier-keyword}.
 
 \begin{describe}{cls}{qualifiable-c-type (c-type) \&key :qualifiers}
   The class @|qualifiable-c-type| describes C types which can bear
@@ -579,7 +579,7 @@ In Sod, the leaf types are
   evaluated).
 
   Each of the @<string>s is associated with the resulting type for retrieval
-  by \descref{find-simple-c-type}{fun}.  Furthermore, a variable
+  by \descref{fun}{find-simple-c-type}.  Furthermore, a variable
   @|c-type-@<name>| is defined, for the first @<name> only, and initialized
   with the newly constructed C type object.
 
@@ -590,7 +590,7 @@ In Sod, the leaf types are
 \begin{describe}{fun}
     {find-simple-c-type @<string> @> @{ @<simple-c-type> @! @|nil| @}}
   If @<string> is the name of a simple C type, as established by the
-  \descref{define-simple-c-type}[macro]{mac}, then return the corresponding
+  \descref{mac}{define-simple-c-type}[macro], then return the corresponding
   @|simple-c-type| object; otherwise, return @|nil|.
 \end{describe}
 
@@ -820,8 +820,8 @@ function type is the type of the function's return value.
   argument name.
 
   A @<default> may be supplied.  If the argument is used in a
-  keyword-argument list (e.g., in a \descref{c-keyword-function-type}
-  [object]{cls}), and the @<default> value is provided and non-nil, then its
+  keyword-argument list (e.g., in a \descref{cls}{c-keyword-function-type}
+  [object]), and the @<default> value is provided and non-nil, then its
   (unescaped) printed representation is used to provide a default value if
   the keyword argument is not supplied by the caller.
 \end{describe}
@@ -973,7 +973,7 @@ function type is the type of the function's return value.
   these circumstances obtains, then the specifier constructs an ordinary
   function type.)
 
-  See the description of \descref{c-function-type}{cls} for how a trailing
+  See the description of \descref{cls}{c-function-type} for how a trailing
   @<form> is handled.
 
   The list of @<arg-name>s and @<arg-type>s describes the positional
@@ -987,7 +987,7 @@ function type is the type of the function's return value.
   accepting the @<arguments>.
 
   If the @<arguments> list contains a @|:keys| marker, then a
-  \descref{c-keyword-function-type}[object]{cls} is returned: those arguments
+  \descref{cls}{c-keyword-function-type}[object] is returned: those arguments
   preceding the @|:keys| marker form the positional argument list, and those
   following the marker form the list of keyword arguments.
 \end{describe}
@@ -1016,7 +1016,7 @@ function type is the type of the function's return value.
 \begin{describe}{fun}{reify-variable-argument-tail @<arguments> @> @<list>}
   If the @<argument> list contains an @|:ellipsis| marker, then replace it
   with a @|va_list|.  The name for the new argument, if any, is taken from
-  the \descref{*sod-ap*}[variable]{var}.  The new list is returned; the
+  the \descref{var}{*sod-ap*}[variable].  The new list is returned; the
   original list is not modified, but may share structure with the new list.
 \end{describe}
 
@@ -1029,7 +1029,7 @@ function type is the type of the function's return value.
   The @<lists> parameter is a list consisting of a number of
   @|(@<report-function> . @<args>)| pairs: in each pair, @<report-function>
   is either nil or a function designator, and @<args> is a list of
-  \descref{argument}{cls} objects.
+  \descref{cls}{argument} objects.
 
   The resulting list contains exactly one argument for each distinct argument
   name appearing in the input @<lists>; this argument will contain the
@@ -1043,7 +1043,7 @@ function type is the type of the function's return value.
   arguments and is expected to return two values:
   \begin{itemize}
   \item a file location @<floc> or other object acceptable to
-    \descref{file-location}{gf}, to be used as the location of the main
+    \descref{gf}{file-location}, to be used as the location of the main
     error; and
   \item an object @<what>, whose printed representation should be a noun
     phrase describing the object for which the argument lists are being
@@ -1056,7 +1056,7 @@ function type is the type of the function's return value.
   for the @<args> lists containing the conflicting argument objects are
   called, in an arbitrary order, with a single argument which is the
   offending @|argument| object; the function is expected to issue information
-  messages (see \descref{info}{fun}) to give more detail for diagnosing the
+  messages (see \descref{fun}{info}) to give more detail for diagnosing the
   conflict.  If a @<report-function> is nil, then nothing happens; this is
   considered poor practice.
 \end{describe}
@@ -1072,7 +1072,7 @@ function type is the type of the function's return value.
   arguments, if any, will be printed by @<print-args>.
 
   The @<print-kernel> function is a standard kernel-printing function
-  following the \descref{pprint-c-type}[protocol]{gf}.
+  following the \descref{gf}{pprint-c-type}[protocol].
 
   The @<print-args> function is given a single argument, which is the
   @<stream> to print on.  It should not print the surrounding parentheses.
@@ -1086,7 +1086,7 @@ function type is the type of the function's return value.
 \begin{describe}{fun}{pprint-argument-list @<args> @<stream> @> @<flag>}
   Print an argument list to @<stream>.
 
-  The @<args> is a list of \descref{argument}[objects]{cls}, optionally
+  The @<args> is a list of \descref{cls}{argument}[objects], optionally
   containing an @|:ellipsis| marker.  The function returns true if any
   arguments were actually printed.
 \end{describe}
diff --git a/doc/concepts.tex b/doc/concepts.tex
index f32aa7e..7e3c1c5 100644
--- a/doc/concepts.tex
+++ b/doc/concepts.tex
@@ -473,12 +473,12 @@ There are three main cases to distinguish.
   a lookup at runtime to find the appropriate offset by which to adjust the
   pointer.  The conversion can be performed using the appropriate generated
   upcast macro (see below); the general case is handled by the macro
-  \descref{SOD_XCHAIN}{mac}.
+  \descref{mac}{SOD_XCHAIN}.
 \item If $B$ is a subclass of~$C$ then the conversion is a \emph{downcast};
   otherwise the conversion is a~\emph{cross-cast}.  In either case, the
   conversion can fail: the object in question might not be an instance of~$B$
-  after all.  The macro \descref{SOD_CONVERT}{mac} and the function
-  \descref{sod_convert}{fun} perform general conversions.  They return a null
+  after all.  The macro \descref{mac}{SOD_CONVERT} and the function
+  \descref{fun}{sod_convert} perform general conversions.  They return a null
   pointer if the conversion fails.  (These are therefore your analogue to the
   \Cplusplus\ @|dynamic_cast<>| operator.)
 \end{itemize}
@@ -924,13 +924,13 @@ Construction of a new instance of a class involves three steps.
   instance's slots, and maybe links it into any external data structures as
   necessary.
 \end{enumerate}
-The \descref{SOD_DECL}[macro]{mac} handles constructing instances with
+The \descref{mac}{SOD_DECL}[macro] handles constructing instances with
 automatic storage duration (`on the stack').  Similarly, the
-\descref{SOD_MAKE}[macro]{mac} and the \descref*{sod_make}{fun} and
-\descref{sod_makev}{fun} functions construct instances allocated from the
+\descref{mac}{SOD_MAKE}[macro] and the \descref*{fun}{sod_make} and
+\descref{fun}{sod_makev} functions construct instances allocated from the
 standard @|malloc| heap.  Programmers can add support for other allocation
-strategies by using the \descref{SOD_INIT}[macro]{mac} and the
-\descref*{sod_init}{fun} and \descref{sod_initv}{fun} functions, which
+strategies by using the \descref{mac}{SOD_INIT}[macro] and the
+\descref*{fun}{sod_init} and \descref{fun}{sod_initv} functions, which
 package up imprinting and initialization.
 
 \subsubsection{Allocation}
@@ -1100,9 +1100,9 @@ steps.
 Teardown alone, for objects which require special deallocation, or for which
 deallocation occurs automatically (e.g., instances with automatic storage
 duration, or instances whose storage will be garbage-collected), is performed
-using the \descref{sod_teardown}[function]{fun}.  Destruction of instances
+using the \descref{fun}{sod_teardown}[function].  Destruction of instances
 allocated from the standard @|malloc| heap is done using the
-\descref{sod_destroy}[function]{fun}.
+\descref{fun}{sod_destroy}[function].
 
 \subsubsection{Teardown}
 Details of teardown are necessarily class-specific, but typically it
@@ -1160,7 +1160,7 @@ class.
 The code which makes the decision to destroy an object may often not be aware
 of the object's direct class.  Low-level details of deallocation often
 require the proper base address of the instance's storage, which can be
-determined using the \descref{SOD_INSTBASE}[macro]{mac}.
+determined using the \descref{mac}{SOD_INSTBASE}[macro].
 
 %%%--------------------------------------------------------------------------
 \section{Metaclasses} \label{sec:concepts.metaclasses}
diff --git a/doc/misc.tex b/doc/misc.tex
index 178e6ef..32e2e75 100644
--- a/doc/misc.tex
+++ b/doc/misc.tex
@@ -398,7 +398,7 @@ be implemented fairly easily using @|merge-lists| below.
      \dhead{gf}{merge-error-candidates @<error> @> @<list>}
      \dhead{gf}{merge-error-present-function @<error> @> @<function>}}
   The @|inconsistent-merge-error| condition class used to represent a failure
-  of the \descref{merge-lists}[function]{fun}.
+  of the \descref{fun}{merge-lists}[function].
 
   The @<candidates> are a list of offending items from the input lists, in
   some order: the error is reporting that the function has failed because it
@@ -533,7 +533,7 @@ to the next column.
   Assume that we are currently at a particular @<line> and @<column> in a
   file, and wish to \emph{unread} @<character>: return an @<old-line> and
   @<old-column> at which we might plausibly re-read the character, so that
-  the next call to \descref{update-position}{fun} will return us to @<line>
+  the next call to \descref{fun}{update-position} will return us to @<line>
   and @<column>.  (Specifically, the @<old-column> will likely be wrong if
   @<character> is a horizontal tab.  It is expected that this won't matter:
   the purpose of this function is to set things up so that the
@@ -572,7 +572,7 @@ to the next column.
   The main purpose for this is to be able to access features of the
   underlying stream which a pretty-printing stream can't proxy.  Most
   notably, this is used by C fragment output, which takes advantage of an
-  underlying \descref{position-aware-output-stream}{cls} to print @|\#line|
+  underlying \descref{cls}{position-aware-output-stream} to print @|\#line|
   directives, so that a C~compiler will blame the original fragment in the
   Sod module source rather than the generated C code.
 \end{describe}
@@ -705,7 +705,7 @@ The following definitions are useful when working with conditions.
 \end{describe}
 
 \begin{describe}{fun}{cerror* @<datum> \&rest @<arguments>}
-  A simplified version of \descref{promiscuous-cerror}{fun} which uses the
+  A simplified version of \descref{fun}{promiscuous-cerror} which uses the
   hardcoded string @|Continue| for the restart.  This makes calling the
   function more similar to other condition-signalling functions, at the
   expense of some usability in environments which don't continue after
diff --git a/doc/runtime.tex b/doc/runtime.tex
index ec06a41..a67d994 100644
--- a/doc/runtime.tex
+++ b/doc/runtime.tex
@@ -107,7 +107,7 @@ There are also (currently) three special keyword names.
   keyword names and argument values, as described above, including the first
   keyword name.  (This is therefore different from the convention used when
   calling keyword argument parser functions: see the description of the
-  \descref{KWSET_PARSEFN}[macro]{mac} for more details about these.)  The
+  \descref{mac}{KWSET_PARSEFN}[macro] for more details about these.)  The
   argument tail may itself contain the special keywords.
 
 \item[kw.tab] This special keyword is followed by \emph{two} argument values:
@@ -158,7 +158,7 @@ lists.  Their use is not essential, but may help prevent errors.
 
   \item Omitting the null terminator is a common mistake, so @|<keyword.h>|
     tries to get the compiler to warn if you miss it.  However, the
-    \descref{KWTAIL}[macro]{mac} introduces an extra real argument
+    \descref{mac}{KWTAIL}[macro] introduces an extra real argument
     @|kwfirst_|, because it's not possible to scan a variable-length argument
     tail if there are no mandatory arguments.  If you use @|KWARGS()|, with
     an empty argument list, then the null terminator is passed as @|kwfirst_|
@@ -261,7 +261,7 @@ definitions of functions which accept keyword arguments.
   *kwfirst_| (to collect the first keyword name), and a variable-length
   argument tail.
 
-  The \descref{KWPARSE}[macro]{mac} assumes that the enclosing function's
+  The \descref{mac}{KWPARSE}[macro] assumes that the enclosing function's
   argument list ends with a @|KWTAIL| marker.
 \end{describe}
 
@@ -357,7 +357,7 @@ keyword arguments.
 
   The function also handles the special @|kw.valist| and @|kw.tab| arguments
   described above (\xref{sec:runtime.keywords.calling}).  If an unrecognized
-  keyword argument is encountered, then \descref{kw_unknown}{fun} is called.
+  keyword argument is encountered, then \descref{fun}{kw_unknown} is called.
 \end{describe}
 
 \subsubsection{Parsing keywords}
@@ -378,21 +378,21 @@ make a function's keyword arguments available to it.
   final keyword argument; a null pointer; and the value zero (signifying an
   empty keyword-argument vector).
 
-  If the variable @<kw> was declared using \descref{KWDECL}{mac} and the
+  If the variable @<kw> was declared using \descref{mac}{KWDECL} and the
   function @|@<set>{}_kwparse| has been defined using
-  \descref{KWSET_PARSEFN}{mac} then the effect is to parse the keyword
+  \descref{mac}{KWSET_PARSEFN} then the effect is to parse the keyword
   arguments passed to the function and set the members of @<kw>
   appropriately.
 \end{describe}
 
 \begin{describe}{mac}[KWPARSE]{KWPARSE(@<set>);}
   The macro @|KWPARSE| (note the lack of underscore) combines
-  \descref{KWDECL}{mac} and \descref{KW_PARSE}{mac}.  It declares and
+  \descref{mac}{KWDECL} and \descref{mac}{KW_PARSE}.  It declares and
   initializes a keyword argument structure variable with the fixed name
   @|kw|, and parses the keyword arguments provided to the enclosing function,
   storing the results in @|kw|.  It assumes that the first keyword name is in
   an argument named @|kwfirst_|, as set up by the
-  \descref{KWTAIL}[marker]{mac}.
+  \descref{mac}{KWTAIL}[marker].
 
   The macro expands both to a variable declaration and a statement: in C89,
   declarations must precede statements, so under C89 rules this macro must
@@ -408,7 +408,7 @@ make a function's keyword arguments available to it.
 \end{describe}
 
 As mentioned above, it is not permitted to define an empty keyword set.
-(Specifically, invoking \descref{KWSET_STRUCT}{mac} for an empty keyword set
+(Specifically, invoking \descref{mac}{KWSET_STRUCT} for an empty keyword set
 would result in attempting to define a structure with no members, which C
 doesn't allow.)  On the other hand, keyword arguments are a useful extension
 mechanism, and it's useful to be able to define a function which doesn't
@@ -416,10 +416,10 @@ currently accept any keywords, but which might in the future be extended to
 allow keyword arguments.
 
 \begin{describe}{mac}[KW_PARSE_EMPTY]{KW_PARSE_EMPTY(@<set>, @<kwfirst>);}
-  This is an analogue to \descref{KW_PARSE}{mac} which checks the keyword
+  This is an analogue to \descref{mac}{KW_PARSE} which checks the keyword
   argument list for a function which accepts no keyword arguments.
 
-  It calls the \descref{kw_parseempty}[function]{fun} with five arguments:
+  It calls the \descref{fun}{kw_parseempty}[function] with five arguments:
   the @<set> name, as a string; the string pointer @<kwfirst>; the address of
   a temporary argument-tail cursor object of type @|va_list|, constructed on
   the assumption that @<kwfirst> is the enclosing function's final keyword
@@ -431,10 +431,10 @@ allow keyword arguments.
 \end{describe}
 
 \begin{describe}{mac}[KWPARSE_EMPTY]{KWPARSE_EMPTY(@<set>);}
-  This is an analogue to \descref{KWPARSE}{mac} which checks that the
+  This is an analogue to \descref{mac}{KWPARSE} which checks that the
   enclosing function has been passed no keyword arguments other than the
   special predefined ones.  It assumes that the first keyword name is in an
-  argument named @|kwfirst_|, as set up by the \descref{KWTAIL}[marker]{mac}.
+  argument named @|kwfirst_|, as set up by the \descref{mac}{KWTAIL}[marker].
 \end{describe}
 
 \begin{describe}{fun}[kw_parseempty]
@@ -447,10 +447,10 @@ allow keyword arguments.
   \xref{sec:runtime.keywords.calling}).
 
   The @<set> argument should point to a null-terminated string: this will be
-  reported as the keyword set name to \descref{kw_unknown}{fun}, though it
+  reported as the keyword set name to \descref{fun}{kw_unknown}, though it
   need not (and likely will not) refer to any defined keyword set.  The
   remaining arguments are as for the keyword parsing functions defined by the
-  \descref{KWSET_PARSEFN}[macro]{mac}.
+  \descref{mac}{KWSET_PARSEFN}[macro].
 \end{describe}
 
 \subsection{Function wrappers} \label{sec:runtime.keywords.wrappers}
@@ -511,7 +511,7 @@ past it; but the only clue provided as to the type is the keyword name, which
 in this case is meaningless.
 
 In this situation, the parser functions generated by
-\descref{KWSET_PARSEFN}{mac} (and the \descref{kw_parseempty}[function]{fun})
+\descref{mac}{KWSET_PARSEFN} (and the \descref{fun}{kw_parseempty}[function])
 call @|kw_unknown|.
 
 \begin{describe}{fun}[kw_unknown]
@@ -521,7 +521,7 @@ call @|kw_unknown|.
   keyword set expected by the caller, as a null-terminated string; and @<kw>
   is the unknown keyword which was encountered.  All that @|kw_unknown| does
   is invoke the function whose address is stored in the global variable
-  \descref{kw_unkhook}{var} with the same arguments.
+  \descref{var}{kw_unkhook} with the same arguments.
 
   This function never returns to its caller: if the @|kw_unkhook| function
   returns (which it shouldn't) then @|kw_unknown| writes a fatal error
@@ -550,11 +550,11 @@ call @|kw_unknown|.
     need different arrangements.  The author is willing to coordinate any
     such efforts.} %
   holds the current unknown-keyword handler function.  It will be invoked by
-  \descref{kw_unknown}{fun}.  The function may take whatever action seems
+  \descref{fun}{kw_unknown}.  The function may take whatever action seems
   appropriate, but should not return to its caller.
 
   Initially, this variable points to the
-  \descref{kw_defunknown}[function]{fun}.
+  \descref{fun}{kw_defunknown}[function].
 \end{describe}
 
 \begin{describe}{fun}[kw_defunknown]
@@ -563,8 +563,8 @@ call @|kw_unknown|.
   the keyword named by @<kw> is not known in the keyword set @<set>, and
   calls \man{abort}{3}.
 
-  This function is the default value of the \descref{kw_unkhook}[hook
-  variable]{var}.
+  This function is the default value of the \descref{var}{kw_unkhook}[hook
+  variable].
 \end{describe}
 
 As an example of the kind of special effect which can be achieved using this
@@ -775,7 +775,7 @@ deallocation, and applications are free to use any suitable mechanism.
 
   Keyword arguments for the initialization message may be provided.  The
   @|SOD_INIT| macro expects a single preprocessor-time argument which is
-  a use of one of \descref*{KWARGS}{mac} or \descref{NO_KWARGS}{mac}; the
+  a use of one of \descref*{mac}{KWARGS} or \descref{mac}{NO_KWARGS}; the
   @|sod_init| function expects the keywords as a variable-length argument
   tail; and @|sod_initv| expects the keywords to be passed indirectly,
   through the captured argument-tail cursor @<ap>.
@@ -791,7 +791,7 @@ deallocation, and applications are free to use any suitable mechanism.
   Tears down an instance of a class, releasing any resources it holds.
 
   This function is a very thin wrapper around sending the
-  \descref*{obj.teardown}{msg} message.  See the description of that message
+  \descref*{msg}{obj.teardown} message.  See the description of that message
   (\autopageref{msg:obj.teardown}) and \xref{sec:concepts.lifecycle.death}
   for details.
 \end{describe}
@@ -810,12 +810,12 @@ The following macro constructs an instance with automatic storage duration.
 
   Keyword arguments for the initialization message may be provided.  The
   macro expects a single preprocessor-time argument which is a use of one of
-  \descref*{KWARGS}{mac} or \descref{NO_KWARGS}{mac}.
+  \descref*{mac}{KWARGS} or \descref{mac}{NO_KWARGS}.
 
   The instance has automatic storage duration: pointers to it will become
   invalid when control exits the scope of the declaration.  If necessary, the
   instance should be torn down before this happens, using the
-  \descref{sod_teardown}[function]{fun}.
+  \descref{fun}{sod_teardown}[function].
 \end{describe}
 
 \subsubsection{Dynamic allocation}
@@ -835,7 +835,7 @@ standard C heap.  They don't work in freestanding implementations where
 
   Keyword arguments for the initialization message may be provided.  The
   @|SOD_MAKE| macro expects a single preprocessor-time argument which is
-  a use of one of \descref*{KWARGS}{mac} or \descref{NO_KWARGS}{mac}; the
+  a use of one of \descref*{mac}{KWARGS} or \descref{mac}{NO_KWARGS}; the
   @|sod_make| function expects the keywords as a variable-length argument
   tail; and @|sod_makev| expects the keywords to be passed indirectly,
   through the captured argument-tail cursor @<ap>.
@@ -843,7 +843,7 @@ standard C heap.  They don't work in freestanding implementations where
   Storage for the new instance will have been allocated using the standard
   @|malloc| function.  The easiest way to destroy the instance, when it is no
   longer needed, is probably to call the
-  \descref{sod_destroy}[function]{fun}.
+  \descref{fun}{sod_destroy}[function].
 
   The return value is an instance pointer for the class @<cls>; the
   @|SOD_MAKE| macro will have converted it to the correct type, so it should
@@ -855,7 +855,7 @@ standard C heap.  They don't work in freestanding implementations where
 
   The pointer @<p> should be an instance pointer, i.e., a pointer to any of
   an instance's chains.  The instance is torn down, by sending it the
-  \descref{obj.teardown}[message]{msg}.  If the instance reports itself ready
+  \descref{msg}{obj.teardown}[message].  If the instance reports itself ready
   for deallocation, then its storage is released using @|free|.  The return
   value is the value returned by the @|obj.teardown| message.
 \end{describe}
diff --git a/doc/sod.sty b/doc/sod.sty
index ffe2b9a..0452348 100644
--- a/doc/sod.sty
+++ b/doc/sod.sty
@@ -362,6 +362,13 @@
 }
 \def\desc@end{\endlist\after@desc\global\let\after@desc\saved@after@desc}
 
+\def\@ifnextchar@preserve#1#2#3{%
+  \let\want@= #1\def\@tempa{#2}\def\@tempb{#3}%
+  \futurelet\nch@\@ifnch@p%
+}
+\def\@ifnch@p{%
+  \ifx\want@\nch@\expandafter\@tempa\else\expandafter\@tempb\fi}
+
 \@namedef{describe*}#1{\desc@begin{#1}}
 \expandafter\let\csname enddescribe*\endcsname\desc@end
 \def\describe{\parse@dhd\desc@}
@@ -371,21 +378,21 @@
 \def\descref{\@ifstar%
   {\descref@i{}\@gobble{}}%
   {\descref@i{ (}{\noexpand\autopageref}{)}}}
-\def\descref@i#1#2#3#4{\@ifnextchar[%
-  {\descref@ii{#1}{#2}{#3}{#4}}%
-  {\descref@iii{#1}{#2}{#3}{#4}{}}}
-\def\descref@ii#1#2#3#4[#5]{\descref@iii{#1}{#2}{#3}{#4}{ #5}}
+\def\descref@i#1#2#3#4#5{\@ifnextchar@preserve[%
+  {\descref@ii{#1}{#2}{#3}{#4}{#5}}%
+  {\descref@iii{#1}{#2}{#3}{#4}{#5}{}}}
+\def\descref@ii#1#2#3#4#5[#6]{\descref@iii{#1}{#2}{#3}{#4}{#5}{ #6}}
 \def\descref@iii#1#2#3#4#5#6{%
   \begingroup%
     \let\protect\@empty%
     \def\@uscore{-\@gobble}%
     \edef\@tempa##1{%
       \endgroup%
-      \noexpand\hyperref[#6:#4]%
+      \noexpand\hyperref[#4:#5]%
       ##1%
-      #2{#6:#4}%
+      #2{#4:#5}%
     }%
-  \@tempa{{\code{#4}}#5#1}#3%
+  \@tempa{{\code{#5}}#6#1}#3%
 }
 
 %%%----- That's all, folks --------------------------------------------------
diff --git a/doc/syntax.tex b/doc/syntax.tex
index 7eed24f..22fb1d8 100644
--- a/doc/syntax.tex
+++ b/doc/syntax.tex
@@ -431,8 +431,8 @@ operators.
 Finally, an S-expression preceded by @|?| causes the expression to be read in
 the current package (which is always @|sod-user| at the start of a module)
 and immediately evaluated (using @|eval|); the resulting value is converted
-into a property value using the \descref{decode-property}[generic
-function]{gf}.
+into a property value using the \descref{gf}{decode-property}[generic
+function].
 
 
 \subsection{Property output types and coercions}
@@ -440,8 +440,8 @@ function]{gf}.
 
 When a property value is inspected by the Sod translator, or an extension, it
 is \emph{coerced} so as to conform to a requested output type.  This coercion
-process is performed by the \descref{coerce-property-value}[generic
-function]{gf}, and additional output types and coercions can be defined by
+process is performed by the \descref{gf}{coerce-property-value}[generic
+function], and additional output types and coercions can be defined by
 extensions.  The built-in output types coercions, from the value types listed
 above, are as follows.
 
-- 
2.11.0

