CHAPTER 13   ASSOCIATED TOOLS


XREF Cross-reference and Symbol Listing Facility


XREF is a tool that creates a cross-referenced symbol table
listing of your program.

To invoke XREF, you must provide a program invocation line,
either typed to the console when the DOS command prompt appears,
or included in a batch file.  The program invocation line
consists of the program name XREF, followed by the name of a .SYM
symbol table file produced by A86 when you assembled your
program.  You do not need to give the .SYM extension. Note that
if you follow normal methodology, the name of the symbol table
file is the same as the name of the program.

XREF will obtain the list of source files from the symbols file,
read those source files, and create a listing file with the same
name as the .SYM file, but with a .XRF extension.

Prior to V3.12, XREF required the list of source files to be
explicitly given, and allowed you to specify the name of the
output file.  To retain compatibility with batch files invoking
the old XREF, the current version ignores anything on the command
tail after the symbols file name.  This means you can no longer
specify a different output file name.  Sorry about that-- I
couldn't think of any other way to be compatible without
overwriting somebody's source files with XREF output.  You can
always rename the file after XREF is completed.

For example, you can type XREF myprog to obtain the cross-
reference for the assembly that produced myprog.SYM.  The output
will be in the file myprog.XRF.

The output of XREF is an alphabetical listing of all the
non-local symbols in your program.  For each symbol, XREF gives
its type, the file in which it was defined, its value, and a list
of all procedures in which the file was used.  If you print this
file, you typically use the TCOLS tool to obtain a multi-column
listing from XREF's single-column output.

Note the use of procedure names to identify references -- this is
unique to the A86 package, and makes the cross-reference listing
truly readable.  Other cross-reference listings give either line
numbers, which are meaningless unless you go find the associated
line; or a file name, which doesn't give you as much useful
information.

Here is a more detailed description of the various pieces of
information provided for each symbol:

1. TYPE.  Labels are indicated by a colon immediately following
   the symbol name.  Special symbols such as macro names are
   denoted by an appropriate word such as "macro" in place of the
   value on the following line.  Other symbol types are described
   by one or two characters, following the symbol name.
   Possibilities for the first character are:
                                                             13-2

        m  for a simple memory variable
        +  for an index memory quantity
        c  for a constant
        i  for an interrupt-equate
        s  for a structure

    If there is a second letter, it is a size attribute: b for
    byte, w for word, f for far (or doubleword).

2. FILE in which the symbol was defined.  The name is stripped of
   its extension, which is presumably the same for all your
   source files.  The name is preceded by = or period, which
   denotes a definition of, not a reference to the symbol.

3. VALUE, given as 4 hex digits, on the line following the
   symbol.  For memory variables, this is the location of the
   variable.  For indexed quantities, this is the
   constant-displacement part of the quantity.  For structures,
   it is the size of the structure.  For interrupt equates, it is
   the number of the interrupt.

4. REFERENCES, given on indented lines following the symbol name.
   All occurrences of the symbol in your program produce a
   reference.  If the symbol is the first thing on a line, it is
   considered a "definition" of that symbol, the reference listed
   is the source file name.  The name is preceded by a period if
   the definition was via a colon (i.e., a label); it is preceded
   by an equals sign otherwise. If the symbol is not the first
   thing on the line, then it is not a definition.  The reference
   listing consists of the name of the last definition that XREF
   scanned (which, if your program is organized in a standard
   way, will be the name of the procedure in which the reference
   occurred.

   Observe that you must use the local-label facility of A86 to
   make this work.  If you don't use local labels as your
   "place-marker" symbols, the symbol XREF gives you will often
   be the name of the last "place-marker" symbol, not the name of
   the last procedure.

   To save space, duplicate reference entries are denoted by a
   single entry, followed by "*n", where n is the decimal number
   of occurrences of that entry.


EXMAC Macro Expansion Tool

There is a tool called EXMAC which will help you troubleshoot A86
program lines that call macros.  If you are not sure about what
code is being generated by your macro calls, EXMAC will tell you.

To use this tool, you must first assemble your macro definitions,
to produce a symbol table file.  A86 will produce a .SYM file
even if there were errors.  If the errors weren't too
catastrophic, the SYM file should be good enough to enable EXMAC
to do its job.
                                                             13-3

EXMAC can be used in two different ways.    First, it can be used
as an interactive program.  You invoke the program in this way by
typing just "EXMAC myprog", where myprog.SYM is the name of the
symbols file.  Then you can type in any number of macro-call
lines.  After each line, the program will display the expanded
program text it produces.  If the program does not think your
line is a macro call, it will simply echo the line back to you.
In this mode, you exit the program by typing control-Z at the
beginning of a line, then terminating the line with the ENTER
(RETURN on some computers) key.  On most IBM-compatible
computers, the control-Z code is also generated by the F6 key,
for convenience.

The second way of using EXMAC is to feed a source file to it.  It
will output the equivalent source file with the macros expanded.
You may then, if you wish, rename the new file as the original
source file, and assemble the new file.  This method is useful if
you get an error on a macro expansion line, and you don't know
where the error came from.   To use EXMAC in this second way, you
simply redirect standard input and output: "EXMAC myprog  <infile
>outfile".  With the redirection, EXMAC will take its input from
the file "infile" instead of the keyboard; and it will send its
output to the file "outfile" instead of the screen.  (If you are
not familiar with redirection of standard input and output, you
might want to read about it in Chapter 6, "Standard Input and
Standard Output", of the MS-DOS reference manual.)


A86LIB Source File Library Tool

There is a tool, A86LIB.COM, available only if you are
registered, that lets you build libraries of source files.  To
use A86LIB, you must first code and debug the A86 source files
that you wish to include in your library.  Then you issue the
command A86LIB followed by the names of the source files.
Wildcards are accepted; so you will typically want to gather the
source files into a single directory, and use the wildcard
specification.  For example, if you use the filename extension .8
for your source files, you can issue the command A86LIB *.8 to
create the library.

The library created consists of a catalog file, always named
A86.LIB, together with the source files that you fed to A86LIB to
create the catalog.

The following observations about A86LIB are in order:

1. Unlike object-code libraries, A86.LIB contains only symbol
   names and file names; it does not contain the code itself. You
   MUST retain the source files used to create A86.LIB, because
   A86 will read those files that it needs after consulting
   A86.LIB to read their names.
                                                             13-4

2. A86LIB records all non-local symbols that start a line, and
   are followed by a colon or an EQU.  (Recall that local symbols
   are those names consisting of a single letter followed by one
   or more decimal digits.)   A86LIB also records all symbols
   appearing on lines starting with the word PUBLIC.

3. If a symbol appears in more than one library source file, it
   will be logged for the first file A86LIB sees, and not the
   subsequent ones.  No error will be reported, unless and until
   A86 tries to assemble both files in one assembly, and sees a
   conflict.

4. A86LIB is simple-minded.  A86LIB does NOT recognize or expand
   macros; nor does it recognize conditional-assembly directives.
   This is because the library files do not stand by themselves;
   the macros and conditional-assembly variables being used might
   well be defined in the main program of the programs accessing
   the library files.

You may update A86.LIB by running A86LIB again; either with new
files or previously-recorded ones.  If A86LIB is given a file it
had already read in a previous run, then A86LIB marks all the
symbols it had logged for the file as deleted, before rereading
the file.  Those symbols that are still in the file are then
"unmarked".  Thus, symbols that have been deleted from the file
disappear functionally from A86.LIB, but still occupy space
within A86.LIB.  What I'm getting at is this: A86LIB will
tolerate alterations in library files quite nicely; but for
optimum storage efficiency you should delete A86.LIB and rebuild
it from scratch any time you delete anything from the library.
A86LIB is so fast that this is never very painful.


Using A86.LIB in A86 Assemblies

Once you have created a library with A86LIB, you access it simply
by calling the procedures in it from your A86 program.  When A86
finishes an assembly and sees that there are undefined symbols in
your program, it will automatically look for copies of A86.LIB in
the current directory (then in other directories, as described in
the next section).  If any of the undefined symbols are found in
the A86.LIB catalog, the files containing them are assembled.
You see this in the list of files output to the console by A86.

The subroutines in your library or libraries are effectively a
permanent part of the A86 language.  They can be called up
effortlessly in your A86 programs.  In time you can build up an
impressive arsenal of library modules, making A86 as easy to
program in as most high-level languages.
                                                             13-5

Environment Variable A86LIB

You can set an environment variable A86LIB to specify which
drives or subdirectories contain A86.LIB files.  The variable
consists of a sequence of path names separated by semicolons,
just like the PATH variable used by the operating system.  For
example, if you include in your AUTOEXEC.BAT file the line

   SET A86LIB=C:\bin\lib;\tools\a86lib

then A86 will look for A86.LIB in the current directory, then it
will look for C:\bin\lib\A86.LIB, then \tools\a86lib\A86.LIB. A86
will keep looking in all three catalog files, assembling the
appropriate source files from any or all of them, until there are
no more undefined symbols, or there are no more source files to
assemble.

For every symbol in an A86.LIB catalog, there is recorded the
name of the library file containing the symbol.  The library file
is assumed to be in the same directory as its A86.LIB file,
unless a complete path name (starting with \ or a drive
specifier) was fed to A86.LIB when A86.LIB was created.


Forcing a Library Search

You may force A86 to assemble library files before moving on to
more of your program's source files.  You do this by placing a
hash sign # (hex code 23) between file names in your invocation
line.  For example, suppose your program has two modules FIRST.8
and LAST.8.  FIRST.8 calls subroutines from your library; but you
need the library files assembled before LAST.8 is assembled. (You
might want this because LAST.8 allocates memory space beyond the
end of your program, which would be the end of LAST.8 if it were
truly the last module.)  You accomplish this by the invocation
line:

  A86 FIRST.8 # LAST.8

Note that there is never any need to force a library search at
the end of your program modules: A86 always makes a library
search there, if you have any undefined symbols.


Listings with A86

A86 does not produce a .LST file, or anything similar to it!  (We
now pause, to allow traditionalists to recover from their
swooning shock.)   OK, everybody back to consciousness?  Good.
Now let's all try to strip away our preconceptions, and look at
things with a fresh viewpoint.

In particular, let's consider what we use a listing file for, and
see how A86 meets those needs.  I've been programming for 20
years; I have generated literally tons of listings. Historically,
here's what I have used listings for:
                                                             13-6

1. To find out what my error messages are.  In the early days of
   Intel, the text editor was so bad that it was actually faster
   to march across the building and physically print the list
   file, than it was to use an editor to find error messages! But
   even with a fast editor, what a pain it is to go into the list
   file, enduring its 120-column wide format on your 80-column
   screen, copy down the errors on paper, then go back to the
   source file to find where the errors were.  Why doesn't the
   assembler just stick the messages directly into your source
   file, where you can view them and edit the source
   simultaneously?  That's what A86, and only A86, does, if you
   want it to.

2. To see what code was generated; those hexadecimal bytes at the
   left of the listing.  That was a real necessity, back in the
   days of hexadecimal debuggers.  There we were, furiously
   patching those hex object bytes.  We needed the listings to
   find our way around the program, while debugging.  Today, we
   have symbolic, disassembling debuggers, such as D86.  The
   power of today's debuggers means that you seldom need to look
   at hex object bytes.  If you do, the debugger can show them to
   you.

3. To get a symbol-table listing.  The necessity of this
   diminishes a great deal when you have a SYMBOLIC debugger; but
   I still like to have a listing from time to time.  So I have
   devised a separate program, XREF, that goes through another
   pass of the source file(s), and creates the most useful
   cross-reference listing.

   You may ask, "Why am I being forced to essentially re-assemble
   my code to get a symbol table, when other assemblers will give
   it to me in the original assembly?"  Don't be fooled.  Those
   other assemblers go through all your source files twice, or
   even three times.  They just do it behind your back, every
   time you want an assembly.  That's one reason why my assembler
   is so much faster than everyone else's.

4. To just look at the code.  I have often in the past needed to
   see that program, spread out on paper, just to get a handle on
   what the program is doing.  But I have needed this less and
   less lately.  Why?  For two reasons.  First, text editors have
   improved.  It's much, much easier than it was before to cruise
   through a file on the screen.  Second, my programs have
   adapted to the screen-viewing methodology.  Almost
   subconsciously, I have started making the conceptual "chunks"
   of my code fit into 1 or 2 24-line screens, rather than 1 or 2
   60-line pages.  This, of course, makes better, more modular
   programs.  (Spaghetti tends to untangle when you chop it up.)
   It's gotten to the point where I can develop (and have
   developed) a 5000-line application, fully debugged, without
   ever making a listing!
                                                             13-7

5. For archival purposes.  I still do this; you should never put
   100% trust in magnetic media.  But I've stripped away the
   reasons for having anything but the source code and the symbol
   table.  So I just copy the source files and the
   cross-reference listing to the printer.  I haven't looked at
   the listings too much; so I haven't bothered with pagination
   control.  If you want to, you can insert form feeds into your
   source; A86 will ignore them.  Or, you can write a simple
   listing tool that recognizes the PAGE directive; A86 ignores
   that directive, also.

As a partial remedy to those who have not been convinced by the
above arguments, I now have a D86 command that sends a
disassembly to a file.  The disassembly is formatted in the style
of an assembler listing file, with locations and hex codes at the
left.  See the D86 manual for details.


Mimicking Tool: FAKE.EXE

As of this writing, Turbo C is aware only of the existence of
Microsoft's MASM for assembling source files it generates.  I
hope to persuade Borland to provide a switch to Turbo C that
causes it to invoke A86 directly.  Until that happens, I offer
the tool FAKE.EXE, that convinces Turbo C that A86 is really
MASM.

To use FAKE.EXE, it must be renamed MASM.EXE in your disk system.
I would have named it MASM myself, except that

1. Bill Gates would probably get mad at me if I did, and

2. You need to decide what to do with your real MASM if you have
   it, before installing FAKE.  You could either place FAKE
   (named MASM.EXE) into the individual directories containing
   Turbo C programs, or you can rename MASM to something like
   MSM.EXE or REALMASM.EXE.

Having renamed FAKE.EXE to MASM.EXE, you may now use the Turbo
C's switch, -B, that allows you to place A86 statements into your
C program.  You don't need to worry about the gory details of
what FAKE does.

If you like gory details, here they are: FAKE filters the command
line handed to it, replacing switches:

   /D becomes =
   /ml becomes +c
   /mx becomes +C
   /E becomes +f

FAKE also eliminates the semicolon, appends .ASM to the source
file name, and turns on the O and S switches.  It then feeds the
resulting filtered command line to A86 for assembly.

