X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/a588c77a273681e3cdc85d15fc44f3ddb7da9224..13c06cf4e05b1a9e1609d88215b343f26650cf3d:/doc/output.tex diff --git a/doc/output.tex b/doc/output.tex index 29a8b4d..456554c 100644 --- a/doc/output.tex +++ b/doc/output.tex @@ -7,7 +7,7 @@ %%%----- Licensing notice --------------------------------------------------- %%% -%%% This file is part of the Sensble Object Design, an object system for C. +%%% This file is part of the Sensible Object Design, an object system for C. %%% %%% SOD is free software; you can redistribute it and/or modify %%% it under the terms of the GNU General Public License as published by @@ -25,7 +25,223 @@ \chapter{The output system} \label{ch:output} +This chapter deals with actually generating output files. It will be of +interest to programmers introducing new layout object classes, or new kinds +of output files. An understanding of the material in +\xref{sec:structures.layout} will prove valuable. + %%%-------------------------------------------------------------------------- +\section{Output sequencing} \label{sec:output.sequencer} + +C compilers are picky about the order in which things are presented to them +in their input; but information about the structure of our classes is +scattered among a variety of different layout objects. It's not the case +that a layout object only contributes to a single localized portion of the +output: for example, a @|vtmsgs| layout object is responsible for declaring +both the appropriate @|struct $C$__vtmsgs_$a$| structure in the header file, +populated with method entry pointers, but also declaring its member in the +enclosing @|struct $C$__vt_$i$| structure. + +One approach would be to have the various layout objects just know how to +call each other in the right order so as to have everything come out +properly. That would make extending the translator, e.g., to add new kinds +of layout objects, rather difficult. And it doesn't let users insert custom +C fragments in flexible ways. + +Instead, there's a clear separation between which things need to be output, +and the order in which they're produced. + +Ordering is handled by a \emph{sequencer} object. A sequencer doesn't know +anything particular about output: its job is simply to do things in a +particular order. It's described here because Sod only uses it for output +scheduling. + +A sequencer maintains a collection of named \emph{items}, each of which has a +name and a list of functions associated with it. A name can be any Lisp +object. Names are compared using @|equal|, so lists can be used to construct +a hierarchical namespace. + +The sequencer also maintains a collection of \emph{constraints}, which take +the form of lists of item names. A constraint of the form @|($N_1$, $N_2$, +$\ldots$, $N_k$)| requires that the item named $N_1$ must be scheduled before +the item named $N_2$, and so on, all of which must be scheduled before the +item named $N_k$. Items with these names do not need to exist or be known to +the sequencer. An item name may appear in any number of constraints, all of +which apply. + +It might be that a collection of constraints is impossible to satisfy: for +example, the set +\begin{center} \codeface + (alice bob) \qquad (bob carol) \qquad (carol alice) +\end{center} +can't be satisfied, since the first constraint requires that @|alice| +precedes @|bob|, but the third says that @|alice| must come after @|carol|, +and the second that @|carol| comes after @|bob|: it's not possible that +@|alice| comes before @|bob| and after @|bob|. In this case, the sequencer +fails and signals an error of type @|inconsistent-merge-error|. + +It is possible, but tedious, to explicitly order an entire collection of +items by adding constraints. In the absence of explicit constraints to order +them, items are ordered according to the order in which constraints naming +them were first added to the sequencer. Items not named in any constraint +are not processed at all. + +For example, suppose we have the following constraints. +\begin{center} \codeface + (perl java) \qquad + (lisp java) \qquad + (python icon) \qquad + (icon perl) +\end{center} +The constraints give us that $@|python| < @|icon| < @|perl| < @|java|$, and +also $@|lisp| < @|java|$. In this case, @|lisp| precedes @|python| because +@|lisp| is mentioned in the second constraint while @|python| isn't mentioned +until the third. So the final processing order is +\begin{center} + @|lisp|, \quad + @|python|, \quad + @|icon|, \quad + @|perl|, \quad + @|java| +\end{center} + + +\begin{describe}{cls}{sequencer-item} + An object of class @|sequencer-item| represents a sequencer item. + Sequencer items maintain a \emph{name} and a list of \emph{functions}. + Names are compared using @|equal|. + + The functions are maintained in \emph{reverse order}, because it's + convenient to be able to add new functions using @|push|. +\end{describe} + +\begin{describe}{fun}{sequencer-item-p @ @> @} + Return non-nil if and only if @ is a @|sequencer-item|. +\end{describe} + +\begin{describe}{fun} + {make-sequencer-item @ \&optional @ @> @} + Create and return a new sequencer item with the given @ and list of + @; the list of functions defaults to nil if omitted. +\end{describe} + +\begin{describe*} + {\dhead{fun}{sequencer-item-name @ @> @} + \dhead{fun}{sequencer-item-functions @ @> @} + \dhead{fun}{setf (sequencer-item-functions @) @}} + These functions read or modify the state of a sequencer @, as + originally established by @|make-sequencer-item|. + + It is an error to modify an item's list of functions during a call to + @|invoke-sequencer-items| on the item's owning sequencer. +\end{describe*} + +\begin{describe}{cls}{sequencer () \&key :constraints} +\end{describe} + +\begin{describe*} + {\dhead{fun}{sequencer-constraints @ @> @} + \dhead{fun}{setf (sequencer-constraints @) @} + \dhead{fun}{sequencer-table @ @> @}} +\end{describe*} + +\begin{describe}{fun}{ensure-sequencer-item @ @ @> @} +\end{describe} + +\begin{describe}{fun}{add-sequencer-constraint @ @} +\end{describe} + +\begin{describe}{fun} + {add-sequencer-item-function @ @ @} +\end{describe} + +\begin{describe}{fun} + {invoke-sequencer-items @ \&rest @} +\end{describe} + +\begin{describe}{gf}{hook-output @ @ @} + \begin{describe}{meth}{t,t} + {hook-output (@ t) (@ t) @} + \end{describe} +\end{describe} + +\begin{describe}{mac} + {sequence-output (@ @) \\ \ind + @[ :constraint (@^*) @] \\ + @{ (@ @
^*) @}^*} +\end{describe} + +%%%-------------------------------------------------------------------------- +\section{Module output} \label{output.module} + +\subsection{Producing output} + +\begin{describe}{gf} + {module-output-file @ @ @ + @> @} + \begin{describe*} + {\dhead{meth}{module,symbol} + {module-output-file \=(@ module) \\ + \>(@ symbol) \\ + \>@ + \nlret @} + \dhead{meth}{module,pathname} + {module-output-file \=(@ module) \\ + \>(@ pathname) \\ + \>@ + \nlret @}} + \end{describe*} +\end{describe} + +\begin{describe}{gf}{write-dependency-file @ @ @} +\end{describe} + +\begin{describe}{fun}{output-module @ @ @} +\end{describe} + + +\subsection{Managing output types} \label{output.module.manage} + +\begin{describe}{fun}{declare-output-type @ @} +\end{describe} + +\begin{describe}{fun}{output-type-pathname @ @> @} +\end{describe} + + +\subsection{Utilities} \label{output.module.utilities} + +\begin{describe}{fun}{banner @ @<output> \&key :blank-line-p} +\end{describe} + +\begin{describe}{fun}{guard-name @<filename> @> @<string>} +\end{describe} + +\begin{describe}{fun} + {one-off-output @<token> @<sequencer> @<item-name> @<function>} +\end{describe} + +%%%-------------------------------------------------------------------------- +\section{Class output} \label{output.class} + +\begin{describe}{var}{*instance-class*} +\end{describe} + +\begin{describe}{gf}{emit-class-typedef @<class> @<stream>} +\end{describe} + +\begin{describe}{gf}{emit-class-object-decl @<class> @<stream>} +\end{describe} + +\begin{describe}{gf}{emit-class-conversion-macro @<class> @<super> @<stream>} +\end{describe} + +\begin{describe*} + {\dhead{gf}{emit-message-macro @<class> @<entry> @<stream>} + \dhead{gf}{emit-message-macro-defn + \=@<class> @<entry> @<varargsp> @<me> \\ + \>@<in-names> @<out-names> @<stream>}} +\end{describe*} %% output for `h' files %% @@ -38,6 +254,9 @@ %% includes %% includes end %% classes start +%% early-user start +%% early-user +%% early-user end %% CLASS banner %% CLASS islots start %% CLASS islots slots @@ -68,6 +287,9 @@ %% CLASS conversions %% CLASS object %% classes end +%% user start +%% user +%% user end %% guard end %% epilogue @@ -77,6 +299,9 @@ %% includes start %% includes %% includes end +%% early-user start +%% early-user +%% early-user end %% classes start %% CLASS banner %% CLASS direct-methods start @@ -105,6 +330,9 @@ %% CLASS object CHAIN-HEAD ichain end %% CLASS object end %% classes end +%% user start +%% user +%% user end %% epilogue %%%----- That's all, folks --------------------------------------------------