\section{Assembly-Language Printing}
\label{sec:printer}

Class [[Printer]] controls printing of Machine-SUIF intermediate files
to assembly language.  Its virtual methods are hooks that allow
target-specific subclasses to customize printing according to the
syntax expected by the assembler for the target system.

\subsection{Class [[Printer]]}

\paragraph{Interface.}

[[Printer]] is an abstract class.  You only construct [[Printer]] objects
for specific targets, for which there are corresponding [[Printer]]
subclasses.

<<class [[Printer]]>>=
class Printer {
  public:
    virtual ~Printer() { }

    FILE* get_file_ptr() const { return out; }
    void set_file_ptr(FILE* the_file_ptr) { out = the_file_ptr; }

    int  get_Gnum() const { return Gnum; }
    void set_Gnum(int n) { Gnum = n; }

    bool get_omit_unwanted_notes() const { return !omit_unwanted_notes; }
    void set_omit_unwanted_notes(bool omit) { omit_unwanted_notes = omit; }

    virtual void print_notes(FileBlock*);
    virtual void print_notes(Instr*);

    virtual void start_comment() = 0;

    virtual void print_instr(Instr *mi) = 0;
    virtual void print_opnd(Opnd o) = 0;

    virtual void print_extern_decl(VarSym *v) = 0;
    virtual void print_file_decl(int fnum, IdString fnam) = 0;

    virtual void print_sym(Sym *s);
    virtual void print_var_def(VarSym *v) = 0;

    virtual void print_global_decl(FileBlock *fb) = 0;
    virtual void print_proc_decl(ProcSym *p) = 0;
    virtual void print_proc_begin(ProcDef *pd) = 0;
    virtual void print_proc_entry(ProcDef *pd, int file_no_for_1st_line) = 0;
    virtual void print_proc_end(ProcDef *pd) = 0;

<<[[Printer]] protected part>>
};
@

Notes on the public methods:

\begin{itemize}
\item [[get_file_ptr]] and [[set_file_ptr]] fetch and store the
      output stream ([[FILE*]]) for the assembly file being generated.
\item [[get_Gnum]] and [[set_Gnum]] fetch and store the size threshold (in
      bytes) at which an initialized value begins to be considered
      ``large''.  Some targets put small static data in a different
      object-file section from large data.
\item [[get_omit_unwanted_notes]] and [[set_omit_unwanted_notes]]  control
      whether annotation printing is selective.  Normally, annotations on
      instructions are printed as comments in the assembly file, but those
      whose keys are in the set [[nonprinting_notes]] are skipped.  By
      calling [[set_omit_unwanted_notes]] with argument [[false]], 
      you turn off selective printing, so that all annotations appear.
\item [[print_notes]] prints the annotations on the object to which it it
      applied.  Global annotations such as those recording the history of a
      file's compilation are attached to the [[FileBlock]] object.  Local
      annotations are attached to individual instructions.  Separate
      overloading of [[print_notes]] lets you control these cases separately.
\item [[start_comment]] is called to print the opening string of an
      assembly-language ``line'' comment, i.e., one that is implicitly
      terminated by the next end-of-line.
\item [[print_instr]] and [[print_opnd]] are the workhorse methods.  They
      are called to print each instruction and each operand, respectively.
\item [[print_extern_decl]] prints the directive that tells the assembler a
      symbol is externally defined, i.e., that its definition cannot be
      seen until link time.
\item [[print_file_decl]] is called to print a directive identifying one of
      the source files contributing to the current object file.  Its
      arguments are the number and the name of a source file.  (The
      numbering gives the order of the files' appearance.  For an obscure
      reason, it starts at 2.)
\item [[print_sym]] prints a symbol reference.  The default implementation
      distinguishes between global and local symbols.  For those local to a
      procedure, it prepends the procedure name and a separating dot
      ([[.]]).  Names of global symbols are printed without adornment.
\item [[print_var_def]] prints the definition of a non-automatic variable,
      which may or may not have an initializer.
\item [[print_global_decl]] is a hook for printing directives that
      condition the assembly of a whole file.  For example, it may control
      the level of assembler optimization.
\item [[print_proc_decl]] is a hook allowing predeclaration of a procedure
      (\emph{not} the procedure's definition).
\item [[print_proc_begin]], [[print_proc_entry]] and [[print_proc_end]] are
      hooks for the key points in the printing of a procedure's code.  The
      [[_begin]] hook typically adjusts the object section (e.g., with a
      [[.text]] directive) and perhaps the prevailing alignment.  The
      [[_entry]] hook typically prints the procedure's prologue and the
      [[_end]] hook prints its epilogue.
\end{itemize}


\paragraph{Specialization.}

Each [[Printer]] object contains a dispatch table that maps
from an opcode to a virtual method for printing an instruction having that
opcode.  This table, called [[print_instr_table]], is initialized when the
target-specific library creates an instance of its own subclass of
[[Printer]].  The methods used as table entries correspond to the four
kinds of instruction in the Machine SUIF implementation; their names are
[[print_instr_alm]], [[print_instr_cti]], [[print_instr_dot]], and
[[print_instr_label]].  To allow for reuse of a target library by an
extender targeting the same machine, there is an extra virtual method
called [[print_instr_user_defd]], which is called when an opcode lies
outside the range covered by the particular [[Printer]] subclass.  This can
be defined by more-derived classes to print additional instructions.

<<[[Printer]] protected part>>=
  protected:
    // table of Instr printing functions -- filled in by derived class
    typedef void (Printer::*print_instr_f)(Instr *);
    Vector<print_instr_f> print_instr_table;

    // printing functions that populate the print_instr_table
    virtual void print_instr_alm(Instr *) = 0;
    virtual void print_instr_cti(Instr *) = 0;
    virtual void print_instr_dot(Instr *) = 0;
    virtual void print_instr_label(Instr *) = 0;

    virtual void print_instr_user_defd(Instr *) = 0;

    Printer();

    // helper
    virtual void print_annote(Annote *the_annote);

    // remaining state
    FILE *out;
    int Gnum;
    bool omit_unwanted_notes;
@

The [[print_annote]] protected method prints a SUIF [[Annote]] object,
which is expected to be a [[BrickAnnote]].

The remaining instance fields are exposed to subclass methods.  For
brevity, printing methods typically use the [[out]] field directly.


\paragraph{The [[Printer]] object for the current target.}

To access the [[Printer]] object in the prevailing context, call this
function:

<<function [[target_printer]]>>=
Printer* target_printer();
@


\subsection{Header file for module [[Printer.h]]}

The interface file has the following layout:

<<printer.h>>=
/* file "machine/printer.h" */

<<Machine-SUIF copyright>>

#ifndef MACHINE_PRINTER_H
#define MACHINE_PRINTER_H

#include <machine/copyright.h>

#ifndef SUPPRESS_PRAGMA_INTERFACE
#pragma interface "machine/printer.h"
#endif

#include <machine/substrate.h>
#include <machine/opnd.h>
#include <machine/machine_ir.h>

<<class [[Printer]]>>

<<function [[target_printer]]>>

#endif /* MACHINE_PRINTER_H */
@
