mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-11-04 11:05:12 +00:00
173 lines
5.8 KiB
Plaintext
173 lines
5.8 KiB
Plaintext
<chapter id="ch3-link">
|
|
<title>Headers, Libraries, and Macros</title>
|
|
|
|
<para>
|
|
In this chapter we will split away parts of our <quote>Hello
|
|
World</quote> program into reusable header files and libraries.
|
|
We will also abstract away our string printing technique into a
|
|
macro which may be invoked at will, on arbitrary strings. We will
|
|
then multiply the output of our program tenfold.
|
|
</para>
|
|
|
|
<section>
|
|
<title>Header files and libraries</title>
|
|
|
|
<para>
|
|
The prelude to our program—the <filename>PRG</filename>
|
|
information and the BASIC program—are going to be the same
|
|
in many, many programs. Thus, we should put them into a header
|
|
file to be included later. The <literal>.include</literal>
|
|
directive will load a file and insert it as source at the
|
|
designated point.
|
|
</para>
|
|
|
|
<para>
|
|
A related directive, <literal>.require</literal>, will include
|
|
the file as long as it hasn't been included yet elsewhere. It
|
|
is useful for ensuring a library is linked in.
|
|
</para>
|
|
|
|
<para>
|
|
For pre-assembled code or raw binary data,
|
|
the <literal>.incbin</literal> directive lets you include the
|
|
contents of a binary file directly in the output. This is handy
|
|
for linking in pre-created graphics or sound data.
|
|
</para>
|
|
|
|
<para>
|
|
If you only wish to include part of a binary
|
|
file, <literal>.incbin</literal> takes up to two optional
|
|
arguments, naming the file offset at which to start reading and
|
|
the number of characters to read.
|
|
</para>
|
|
|
|
<para>
|
|
As a sample library, we will expand the definition of
|
|
the <literal>chrout</literal> routine to include the standard
|
|
names for every KERNAL routine. Our header file will
|
|
then <literal>.require</literal> it.
|
|
</para>
|
|
|
|
<para>
|
|
We'll also add some convenience aliases for things like reverse
|
|
video, color changes, and shifting between upper case/graphics
|
|
and mixed case text. We'd feed those to
|
|
the <literal>chrout</literal> routine to get their effects.
|
|
</para>
|
|
|
|
<para>
|
|
Since there have been no interesting changes to the prelude, and
|
|
the KERNAL values are standard, we do not reproduce them here.
|
|
(The files in question are <xref linkend="c64-1-src"
|
|
endterm="c64-1-fname"> and <xref linkend="kernal-src"
|
|
endterm="kernal-fname">.) The <filename>c64kernal.oph</filename>
|
|
header is likely to be useful in your own projects, and it is
|
|
available in the <literal>platform/</literal> directory for easy
|
|
inclusion.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Macros</title>
|
|
|
|
<para>
|
|
A macro is a way of expressing a lot of code or data with a
|
|
simple shorthand. It's also usually configurable. Traditional
|
|
macro systems such as C's <literal>#define</literal> mechanic
|
|
use <emphasis>textual replacement</emphasis>: a macro is
|
|
expanded before any evaluation or even parsing occurs.
|
|
</para>
|
|
|
|
<para>
|
|
In contrast, Ophis's macro system uses a <emphasis>call by
|
|
value</emphasis> approach where the arguments to macros are
|
|
evaluated to bytes or words before being inserted into the macro
|
|
body. This produces effects much closer to those of a
|
|
traditional function call. A more detailed discussion of the
|
|
tradeoffs may be found in <xref linkend="ref-link">.
|
|
</para>
|
|
|
|
<section>
|
|
<title>Macro definitions</title>
|
|
|
|
<para>
|
|
A macro definition is a set of statements between
|
|
a <literal>.macro</literal> statement and
|
|
a <literal>.macend</literal> statement.
|
|
The <literal>.macro</literal> statement also names the macro
|
|
being defined.
|
|
</para>
|
|
|
|
<para>
|
|
No global or anonymous labels may be defined inside a macro:
|
|
temporary labels only persist in the macro expansion itself.
|
|
(Each macro body has its own scope. A label map will trace
|
|
back through macro expansions to describe were a label inside
|
|
a macro body came from.)
|
|
</para>
|
|
|
|
<para>
|
|
Arguments to macros are referred to by number: the first is
|
|
<literal>_1</literal>, the second <literal>_2</literal>, and so on.
|
|
</para>
|
|
|
|
<para>
|
|
Here's a macro that encapsulates the printing routine in our
|
|
<quote>Hello World</quote> program, with an argument being the
|
|
address of the string to print:
|
|
</para>
|
|
|
|
<programlisting>
|
|
.macro print
|
|
ldx #0
|
|
_loop: lda _1, x
|
|
beq _done
|
|
jsr chrout
|
|
inx
|
|
bne _loop
|
|
_done:
|
|
.macend
|
|
</programlisting>
|
|
|
|
</section>
|
|
<section>
|
|
<title>Macro invocations</title>
|
|
|
|
<para>
|
|
Macros may be invoked in two ways: one that looks like a
|
|
directive, and one that looks like an instruction.
|
|
</para>
|
|
|
|
<para>
|
|
The most common way to invoke a macro is to backquote the name
|
|
of the macro. It is also possible to use
|
|
the <literal>.invoke</literal> command. These commands look
|
|
like this:
|
|
</para>
|
|
|
|
<programlisting>
|
|
`print msg
|
|
.invoke print msg
|
|
</programlisting>
|
|
|
|
<para>
|
|
Arguments are passed to the macro as a comma-separated list.
|
|
They must all be expressions that evaluate to byte or word
|
|
values—a mechanism similar to <literal>.alias</literal>
|
|
is used to assign their values to the <literal>_n</literal>
|
|
names.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Example code</title>
|
|
|
|
<para>
|
|
<xref linkend="tutor3-src" endterm="tutor3-fname"> expands our
|
|
running example, including the code above and also defining a
|
|
new macro <literal>greet</literal> that takes a string argument
|
|
and prints a greeting to it. It then greets far too many
|
|
targets.
|
|
</para>
|
|
</section>
|
|
</chapter>
|