[comp.sources.amiga] v02i029: dasm - small systems cross assembler V2.0, Part03/03

page@swan.ulowell.edu (Bob Page) (10/27/88)

Submitted-by: dillon@cory.berkeley.edu (Matt Dillon)
Posting-number: Volume 2, Issue 29
Archive-name: languages/dasm20.3

# This is a shell archive.  Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have default permissions).
# This archive contains the following files:
#	README
#	TODO
#	doc/ftohex.doc
#	doc/dasm.doc
#	src/test.asm
#	src/tags
#	src/test
#	src/mne68705.c
#	src/ftohex.c
#	src/symbols.c
#
if `test ! -s README`
then
echo "writing README"
cat > README << '\Rogue\Monster\'

    DASM    V2.0

    (c)Copyright 1988 Matthew Dillon, All Rights Reserved.
       Freely Distributable (for non-profit) ONLY.  No redistribution
       of any modified text files or redistribution of a subset of the
       source is allowed.  Redistribution of modified binaries IS allowed
       under the above terms.

       Circumvention of said terms requires the permission of the Author
       via US Mail.

       Matthew Dillon
       891 Regal Rd.
       Berkeley, Ca. 94708


COMPILATION

    The source code assumes that integers are LONG WORDS.  All expression
    computation is carried out with 32 bit ints.  Additionaly, the
    correct implementation of STDIO functions is assumed (no translation).

    This code will compile with little or no modification on Amiga and UNIX
    systems.

CONVERSION TO IBM:

    FTOHEX should compile on an IBM-PC, DASM will not.

    Compilers on IBM PC's are usually not very sophisticated (at least not
    compared to what I'm used to), and must deal with two major problems:
    (1) 16 bit integers, (2) incompatible text file format with CR-LF
    instead of just LF.  To convert to an IBM PC compiler, you must

    (A) Declare all unspecified functions as returning a LONG
    (B) Put in extern's in ASM.H for all unspecified functions
	declaring them as returning a LONG
    (C) Change any int declarations to long
    (D) Ensure all expressions are carried out on longwords (especially
	expression handling)
    (E) Ensure all function calls pass longwords by adding a (long) cast
	or 'L' at the end of longword constants.
    (F) Ensure STDIO for any binary files (the output file) does NOT
	do data translation.

    Alternately, you can throw away your IBM and go for a better machine.


    DASM:	The Assembler

    FTOHEX:	Convert assembler output files to intel-hex format


FEATURES

    -fast
    -processor selection (use same assembler for many processors)
    -multi-pass (more than two passes if required)
    -conditional assembly
    -local labels (VERY local labels)
    -macro capability (no stacking limit)
    -symbolic expression capability
    -addressing mode overides
    -arbitrary number of named segments
    -many pseudo-ops for repeat loops, data generation, etc....


PROCESSORS

      --------------- CURRENTLY SUPPORTED MICROPROCESSORS ---------------


6502:	    ORDER LSB,MSB   A<7:0> X<7:0> Y<7:0>    RelAddr:   .+ilen+offset
68705:	    ORDER MSB,LSB   A<7:0> X<7:0>	    RelAddr:   .+ilen+offset
6803/HD6303:ORDER MSB,LSB   A<7:0> B<7:0> X<15:0>   RelAddr:   .+ilen+offset


ADDRESSING MODES		6502	68705	6803/HD6303
BYTES

 2  implied			x	x	x
 2  immediate.8     #byte	x	x	x
 3  immediate.16    #word			x
 2  byteaddr	    byte	x	x	x
 2  byteaddr,x	    byte,x	x	x	x
 2  byteaddr,y	    byte,y	x
 3  wordaddr	    word	x	x	x
 3  wordaddr,x	    word,x	x	x
 3  wordaddr,y	    word,y	x
 2  relative	    byte	x	x	x
 2  ind.byte.x	    (byte,x)    x
 2  ind.byte.y	    (byte),y    x
 3  ind.word	    (word)      x
 1  0,x 	    [0],x		x
 2  bitmod	    #no,badr		x		baseinst + 2*bitno
 3  bitbramod	    #no,badr,rel	x		baseinst + 2*bitno

NOTE:	HD6303 instruction extensions over the 6803 are:
	    AIM OIM EIM TIM XGDX SLP

\Rogue\Monster\
else
  echo "will not over write README"
fi
if [ `wc -c README | awk '{printf $1}'` -ne 3211 ]
then
echo `wc -c README | awk '{print "Got " $1 ", Expected " 3211}'`
fi
if `test ! -s TODO`
then
echo "writing TODO"
cat > TODO << '\Rogue\Monster\'

    -DS.W   , allow word-sized fill characters
    -DS.L   , allow long-sized fill characters

\Rogue\Monster\
else
  echo "will not over write TODO"
fi
if [ `wc -c TODO | awk '{printf $1}'` -ne 96 ]
then
echo `wc -c TODO | awk '{print "Got " $1 ", Expected " 96}'`
fi
if `test ! -d doc`
then
  mkdir doc
  echo "mkdir doc"
fi
if `test ! -s doc/ftohex.doc`
then
echo "writing doc/ftohex.doc"
cat > doc/ftohex.doc << '\Rogue\Monster\'

FTOHEX	Convert assembly output file to INTEL-HEX format suitable for, say,
a GTEK prom programmer.

    FTOHEX format infile outfile

Example:
    DASM -f2 example.asm -oram:example.out
    FTOHEX 2 ram:example.out ram:example.hex

    This program converts and output file generated by DASM to the Intel
    hex-ascii format.  You must specify the format you used when you
    assembled the source for FTOHEX to properly read the out file.
    Generally format 2 is used for assembly (see DASM.DOC) as this
    generates the smallest hex file.



\Rogue\Monster\
else
  echo "will not over write doc/ftohex.doc"
fi
if [ `wc -c doc/ftohex.doc | awk '{printf $1}'` -ne 549 ]
then
echo `wc -c doc/ftohex.doc | awk '{print "Got " $1 ", Expected " 549}'`
fi
if `test ! -s doc/dasm.doc`
then
echo "writing doc/dasm.doc"
cat > doc/dasm.doc << '\Rogue\Monster\'


DOCUMENTATION FOR DASM V2.11, a high level macro cross assembler for:

	-6502
	-68705
	-6803
	-HD6303 (extension of 6803)

	Soon will work for 68HC11 (next ver)

    (C)Copyright 1987,1988 Matthew Dillon, All Rights Reserved

    Publicly distributable for non-profit only.  Must be distributed
    as is, with NO CHANGES to the documentation or code.  If you want
    your (general) changes to be made part of the distribution, send
    them to me.

    Over the last year my work has included writing software to drive small
    single-chip microcomputers for various things (remote telemetry units,
    for instance).  I have had need to program quite a few different
    processors over that time.

    At the beginning, I used an awful macro assembler running on an IBM-PC.
    I *really* wanted to do it on my Amiga.  Thus the writing of this
    program.

    Feel free to suggest other similar processors for me to add to the list!
    The processor type is specified with a pseudo-op (see below).  This
    assembler produces only binary output in one of three formats described
    below.  In general, one has a master assembly file which INCLUDEs all
    the modules.

    Also provided is FTOHEX which converts an output file in one of the
    three formats to an intel-hex format suitable for many intelligent
    prom programmers (I have a GTEK).

    YES it's packed with features!

FEATURES:

    -fast assembly
    -supports several common 8 bit processor models (NOT 8086, thank god!)
    -takes as many passes as needed
    -automatic checksum generation, special symbol '...'
    -several binary output formats available.  Format 2 allows reverse
     indexed origins.
    -multiple segments, BSS segments (no generation), relocatable origin.
    -expressions, as in C but [] is used instead of () for parenthesis.
     (all expressions are computed with 32 bit integers)
    -no real limitation on label size, label values are 32 bits.
    -complex pseudo ops, repeat loops, macros, etc....


COMMAND LINE:

	asm srcfile [options]

	options:    -f#     select output format 1-3 (default 1, see below)
		    -oname  select output file name (else a.out)
		    -lname  select list file name   (else none generated)
		    -sname  select symbol dump file (else none generated)
		    -v#     select verboseness 0-4 (default 0, see below)
		    -d	    debug mode
		    -DSYMBOL		    predefine a symbol, set to 0
		    -DSYMBOL=EXPRESSION     predefine a symbol, set to exp

	Note: file names should be in RAM: for speed.  If a list file is
	specified, it should be in the RAM: disk (assembly is slowed down
	quite a bit anyway).

	Example:    asm master.asm -f2 -oram:out -lram:list -v3 -DVER=4

FORMAT OPTIONS:

    1  (DEFAULT)

	The output file contains a two byte origin in LSB,MSB order, then
	data until the end of the file.

	Restrictions:	Any instructions which generate output (within an
	initialized segment) must do so with an ascending PC.  Initialized
	segments must occur in ascending order.

    2  RAS (Random Access Segment)

	The output file contains one or more hunks.  Each hunk consists
	of a 2 byte origin (LSB,MSB), 2 byte length (LSB,MSB), and that
	number of data bytes.  The hunks occur in the same order as
	initialized segments in the assembly.  There are no restrictions
	to segment ordering (i.e. reverse indexed ORG statements are
	allowed).  The next hunk begins after the previous hunk's data,
	until the end of the file.

    3  RAW (Raw)

	The output file contains data only (format #1 without the 2 byte
	header).  Restrictions are the same as for format #1.

	Format 3    RAW (Raw format)
	    Same as format 1, but NO header origin is generated.  You get
	    nothing but data.

VERBOSE OPTIONS:

    0	(default)

	Only warnings and errors are generated

    1
	-Segment list information generated after each pass
	-Include file names are displayed
	-statistics on why the assembler is going to make another pass
	    R1,R2 reason code: R3
	    where R1 is the number of times the assembler encountered
	    something requiring another pass to resolve.  R2 is the
	    number of references to unknown symbols which occured in the
	    pass (but only R1 determines the need for another pass).  R3
	    is a BITMASK of the reasons why another pass is required.
	    See the end of this document for bit designations.

    2
	mismatches between program labels and equates are displayed
	on every pass (usually none occur in the first pass unless you
	have re-declared a symbol name).

	displayed information for symbols:
	    ???? = unknown value
	    str  = symbol is a string
	    eqm  = symbol is an eqm macro
	    (r)  = symbol has been referenced
	    (s)  = symbol created with SET or EQM pseudo-op

    3
	    Unresolved and unreferenced symbols are displayed every pass
	    (unsorted, sorry)

    4
	    An entire symbol list is displayed every pass to STDOUT.
	    (unsorted, sorry)

PROCESSOR MODEL:

    The processor model is chosen with the PROCESSOR pseudo-op and should
    be the first thing you do in your assembly file.   Different processor
    models use different integer formats (see below).  The word order does
    not effect the headers in the output files (-f1 and -f2), which are
    always LSB,MSB.  The word ordering effects all address, word, and
    long generation.

    Only one PROCESSOR pseudo-op may be declared in the entire assembly,
    and should be the first thing encountered.

	-6502	    LSB,MSB
	-68HC11     MSB,LSB (next release)
	-68705	    MSB,LSB
	-6803	    MSB,LSB
	-HD6303     MSB,LSB

SEGMENTS:
    The SEG pseudo-op creates/sets the current segment.  Each segment has
    it's own origin and is optionally an 'uninitialized' segment.
    Unitialized segments produce no output and have no restrictions.  This
    is useful for determining the size of a certain assembly sequence
    without generating code, and for assigning RAM to labels.

    'Initialized' segments produce output.  The following should be
    considered when generating roms:

    (1) The default fill character when using ORG (and format 1 or 3) to
	skip forward is 00.  This is a GLOBAL default and effects all
	segments.  See ORG.

    (2) The default fill character for DS is 00 and is independant of
	the default fill character for ORG (see DS).

GENERAL:
    Most everything is recursive.  You cannot have a macro DEFINITION
    within a macro definition, but can nest macro calls, repeat loops,
    and include files.

    The other major feature in this assembler is the SUBROUTINE pseudo-op,
    which logically separates local labels (starting with a dot).  This
    allows you to reuse label names (for example, .1 .fail) rather than
    think up crazy combinations of the current subroutine to keep it all
    unique.

    Almost nothing need be resolved in pass 1.	The assembler will make
    multiple passes in an attempt to resolve the assembly (including just
    one pass if everything is resolved immediately).


PSEUDOPS:

	INCLUDE     "name"

	    Include another assembly file.

[label] SEG[.U]     name

	    This sets the current segment, creating it if neccessary.  If
	    a .U extension is specified on segment creation, the segment
	    is an UNINITIALIZED segment.  The .U is not needed when going
	    back to an already created uninitialized segment, though it
	    makes the code more readable.

[label] DC[.BWL]    exp,exp,exp ...

	    Declare data in the current segment.  No output is generated if
	    within a .U segment.  Note that the byte ordering for the
	    selected processor is used for each entry.

	    The default size extension is a byte.

[label] DS[.BWL]    exp[,filler]

	    declare space (default filler is 0). Data is not generated if
	    within an uninitialized segment.  Note that the number of bytes
	    generated is exp * entrysize (1,2, or 4)

	    The default size extension is a byte.

	    Note that the default filler is always 0 (has nothing to do
	    with the ORG default filler).

[label] DV[.BWL]    eqmlabel exp,exp,exp....

	    This is equivalent to DC, but each exp in the list is passed
	    through the symbolic expression specified by the EQM label.
	    The expression is held in a special symbol dotdot '..' on each
	    call to the EQM label.

	    See EQM below

[label] HEX	    hh hh hh..

	    This sets down raw HEX data.  Spaces are optional between bytes.
	    NO EXPRESSIONS are allowed.  Note that you do NOT place a $
	    in front of the digits.  This is a short form for creating
	    tables compactly.  Data is always layed down on a byte-by-byte
	    basis.

	    Example:	    HEX 1A45 45 13254F 3E12

	ERR

	    Abort assembly.

[label] ORG	    exp[,DefaultFillVal]

	    This pseudop sets the current origin.  You can also set the
	    global default fill character (a byte value) with this
	    pseudoop.  NOTE that no filler is generated until the first
	    data-generating opcode/psueoop is encountered after this one.
	    Sequences like:

		org  0,255
		org  100,0
		org  200
		dc   23

	    will result in 200 zero's and a 23. This allows you to specify
	    some ORG, then change your mind and specify some other (lower
	    address) ORG without causing an error (assuming nothing is
	    generated inbetween).

	    Normally, DS and ALIGN are used to generate specific filler
	    values.

[label] RORG	    exp

	    This activates the relocatable origin.  All generated
	    addresses, including '.', although physically placed at the
	    true origin, will use values from the relocatable origin.
	    While in effect both the physical origin and relocatable origin
	    are updated.

	    The relocatable origin can skip around (no limitations).  The
	    relocatable origin is a function of the segment.  That is, you
	    can still SEG to another segment that does not have a
	    relocatable origin activated, do other (independant) stuff
	    there, and then switch back to the current segment and continue
	    where you left off.

	PROCESSOR model

	    do not quote.  model is one of: 6502,6803,HD6303,68705,68HC11
	    Can only be executed once, and should be the first thing
	    encountered by the assembler.  the 68HC11 will be available
	    next release.

	ECHO exp,exp,exp

	    The expressions (which may also be strings), are echod on the
	    screen and into the list file

[label] REND

	    Deactivate the relocatable origin for the current segment.
	    Generation uses the real origin for reference.

[label] ALIGN	    N[,fill]

	    Align the current PC to an N byte boundry.	The default
	    fill character is always 0, and has nothing to do with
	    the default fill character specifiable in an ORG.

[label] SUBROUTINE  name

	    This isn't really a subroutine, but a boundry between sets of
	    temporary labels (which begin with a dot).  Temporary label
	    names are unique within segments of code bounded by SUBROUTINE:

		CHARLIE subroutine
			ldx #10
		.1	dex
			bne .1
		BEN	subroutine
			ldx #20
		.qq	dex
			bne .qq

	    Automatic temporary label boundries occur for each macro level.
	    Usually temporary labels are used in macros and within actual
	    subroutines (so you don't have to think up a thousand different
	    names)


symbol	EQU	    exp

	    The expression is evaluated and the result assigned to the
	    symbol.

symbol	EQM	    exp

	    The STRING representing the expression is assigned to the
	    symbol.  Occurances of the label in later expressions causes
	    the string to be evaluated for each occurance.  Also used in
	    conjuction with the DV psuedo-op.

symbol	SET	    exp

	    Same as EQU, but the symbol may be reassigned later.

	MAC	    name

	    Declare a macro.  lines between MAC and ENDM are the macro.
	    You cannot recursively declare a macro.  You CAN recursively
	    use a macro (reference a macro in a macro).  No label is
	    allowed to the left of MAC or ENDM.

	    Arguments passed to macros are referenced with: {#}.  The first
	    argument passed to a macro would thus be {1}.  You should
	    always use LOCAL labels (.name) inside macros which you use
	    more than once. {0} represents an EXACT substitution of the
	    ENTIRE argument line.

	ENDM

	    end of macro def.  NO LABEL ALLOWED ON THE LEFT!

	MEXIT

	    Used in conjuction with conditionals.  Exits the current macro
	    level.

[label] IFCONST     exp

	    Is TRUE if the expression result is defined,  FALSE otherwise
	    and NO error is generated if the expression is undefined.

[label] IFNCONST    exp

	    Is TRUE if the expression result is undefined, FALSE otherwise
	    and NO error is generated if the expression is undefined.

[label] IF	    exp

	    Is TRUE if the expression result is defined AND non-zero.
	    Is FALSE if the expression result is defined AND zero.
	    Neither IF or ELSE will be executed if the expression result
	    is undefined.  If the expression is undefined, another assembly
	    pass is automatically taken.

[label] ELSE

	    ELSE the current IF.

[label] ENDIF
[label] EIF

	    Terminate an IF. ENDIF and EIF are equivalent.

[label] REPEAT	    exp
[label] REPEND

	    Repeat code between REPEAT/REPEND 'exp' times.  if exp == 0,
	    the code repeats forever.  exp is evaluated once.

		Y   SET     0
		    REPEAT  10
		X   SET     0
		    REPEAT  10
		    DC	    X,Y
		X   SET     X + 1
		    REPEND
		Y   SET     Y + 1
		    REPEND

	    generates an output table:	0,0 1,0 2,0 ... 9,0  0,1 1,1 2,1
	    ... 9,1, etc...

	    Labels within a REPEAT/REPEND should be temporary labels with a
	    SUBROUTINE pseudoop to keep them unique.

	    The Label to the left of REPEND is assigned AFTER the loop
	    FINISHES.


[label] XXX[.force] operand

	    XXX is some mnemonic, not necessarily three characters long.
	    The .FORCE optional extension is used to force specific
	    addressing modes (see below).

GENERAL:

    The label will be set to the current ORG/RORG either before or after
    a pseudo-op is executed.  Most of the time, the label to the left of a
    pseudo-op is the current ORG/RORG. The following pseudo-op's labels are
    created AFTER execution of the pseudo-op:

	SEG, ORG, RORG, REND, ALIGN

EXTENSIONS:

    FORCE extensions are used to force an addressing mode.  In some cases,
    you can optimize the assembly to take fewer passes by telling it the
    addressing mode.  Force extensions are also used with DS,DC, and DV
    to determine the element size.  NOT ALL EXTENSIONS APPLY TO ALL
    PROCESSORS!

	example:    lda.z   charlie

	i   -implied
	ind -indirect word
	0   -implied
	0x  -implied indexing (0,x)
	0y  -implied indexing (0,y)
	b   -byte address
	bx  -byte address indexed x
	by  -byte address indexed y
	w   -word address
	wx  -word address indexed x
	wy  -word address indexed y
	l   -longword (4 bytes) (DS/DC/DV)
	r   -relative
	u   -uninitialized (SEG)

	First character equivalent substitutions:

	b z d	    (byte, zeropage, direct)
	w e a	    (word, extended, absolute)


ASSEMBLER PASSES:
    The assembler may have to make several passes through the source
    code to resolve all generation.  The number of passes is not
    limited to two.  Since this may result in an unexpected, verbose
    option 2, 3, and 4 have been provided to allow determination of the
    cause. The assembler will give up if it thinks it can't do the
    assembly in *any* number of passes.

    Error reporting could be better....


EXPRESSIONS:
	[] may be used to group expressions.  The precedense of operators
	is the same as for the C language in almost all respects.  Use
	brackets [] when you are unsure.  The reason () cannot be used to
	group expressions is due to a conflict with the 6502 and other
	assembly languages.

	Some operators, such as ||, can return a resolved value even if
	one of the expressions is not resolved.   Operators are as follows:

	NOTE WELL!  Some operations will result in non-byte values when a
	byte value was wanted.	For example:	~1  is NOT $FF, but
	$FFFFFFFF.  Preceding it with a < (take LSB of) will solve the
	problem.  ALL ARITHMETIC IS CARRIED OUT IN 32 BITS.  The final
	Result will be automatically truncated to the maximum handleable
	by the particular machine language (usually a word) when applied
	to standard mnemonics.

	prec	    UNARY

	20  ~exp    one's complement.
	20  -exp    negation
	20  !exp    not expression (returns 0 if exp non-zero, 1 if exp zero)
	20  <exp    take LSB byte of a 16 bit expression
	20  >exp    take MSB byte of an expression

		    BINARY

	19  *	    multiplication
	19  /	    division
	19  %	    mod
	18  +	    addition
	18  -	    subtraction
	17  >>,<<   shift right, shift left
	16  >,>=    greater, greater equal
	16  <,<=    smaller, smaller equal
	15  ==	    equal to.  Try to use this instead of =
	15  =	    exactly the same as == (exists compatibility)
	15  !=	    not equal to
	14  &	    logical and
	13  ^	    logical xor
	12  |	    logical or
	11  &&	    left expression is true AND right expression is true
	10  ||	    left expression is true OR right expression is true
	 9  ?	    if left expression is true, result is right expression,
		    else result is 0.	[10 ? 20] returns 20
	 8  []	    group expressions
	 7  ,	    separate expressions in list (also used in
		    addressing mode resolution, BE CAREFUL!

    Constants:

	nnn	decimal
	0nnn	octal
	%nnn	binary
	$nnn	hex
	'c      character
	"cc.."  string (NOT zero terminated if in DC/DS/DV)
	[exp]d	the constant expressions is evaluated and it's decimal
		result turned into an ascii string.

    Symbols:

	...	-holds CHECKSUM so far (of actual-generated stuff)
	..	-holds evaluated value in DV pseudo op
	.name	-represents a temporary symbol name.  Temporary symbols
		 may be reused inside MACROS and between SUBROUTINES, but
		 may not be referenced across macros or across SUBROUTINEs.
	.	-current program counter (as of the beginning of the
		 instruction).
	name	-beginning with an alpha character and containing letters,
		 numbers, or '_'.  Represents some global symbol name.


WHY codes:
    Each bit in the WHY word (verbose option 1) is a reason (why
    the assembler needs to do another pass), as follows:

    bit 0   expression in mnemonic not resolved
	1   -
	2   expression in a DC not resolved
	3   expression in a DV not resolved (probably in DV's EQM symbol)
	4   expression in a DV not resolved (could be in DV's EQM symbol)
	5   expression in a DS not resolved
	6   expression in an ALIGN not resolved
	7   ALIGN: Relocatable origin not known (if in RORG at the time)
	8   ALIGN: Normal origin not known	(if in ORG at the time)
	9   EQU:   expression not resolved
	10  EQU:   value mismatch from previous pass (phase error)
	11  IF:     expression not resolved
	12  REPEAT: expression not resolved

	13  a program label has been defined after it has been
	    referenced (forward reference) and thus we need another
	    pass
	14  a program label's value is different from that of the
	    previous pass (phase error)

    Certain errors will cause the assembly to abort immediately, others
    will wait until the current pass is other.	The remaining allow another
    pass to occur in the hopes the error will fix itself.


VERSIONS:

    V2.11
	-Fixed <exp >exp bug, <exp now means LSB, >exp MSB (it used to
	 be reversed).
	-Fixed many bugs in macros and other things
	-Added automatic checksumming ... no more doing checksums manually!
	-Added several new processors, including 6502.
	-Source is now 16/32 bit int compatible, and will compile on an
	 IBM-PC (the ultimate portability test)

    V2.01

	-can now have REPEAT/REPEND's within macros
	-fill field for DS.W is a word (used to be a byte fill)
	-fill field for DS.L is a long (used to be a byte fill)


\Rogue\Monster\
else
  echo "will not over write doc/dasm.doc"
fi
if [ `wc -c doc/dasm.doc | awk '{printf $1}'` -ne 19789 ]
then
echo `wc -c doc/dasm.doc | awk '{print "Got " $1 ", Expected " 19789}'`
fi
if `test ! -d src`
then
  mkdir src
  echo "mkdir src"
fi
if `test ! -s src/test.asm`
then
echo "writing src/test.asm"
cat > src/test.asm << '\Rogue\Monster\'

	    trace   on

X	    equ     $100
IRAMSTART   equ     $80

	    org     X
	    org     IRAMSTART

\Rogue\Monster\
else
  echo "will not over write src/test.asm"
fi
if [ `wc -c src/test.asm | awk '{printf $1}'` -ne 101 ]
then
echo `wc -c src/test.asm | awk '{print "Got " $1 ", Expected " 101}'`
fi
if `test ! -s src/tags`
then
echo "writing src/tags"
cat > src/tags << '\Rogue\Monster\'
eval exp.c /^eval(
alphanum exp.c /^alphanum(
evaltop exp.c /^evaltop(
stackarg exp.c /^stackarg(
doop exp.c /^doop(
op_takelsb exp.c /^op_takelsb(
op_takemsb exp.c /^op_takemsb(
op_negate exp.c /^op_negate(
op_invert exp.c /^op_invert(
op_not exp.c /^op_not(
op_mult exp.c /^op_mult(
op_div exp.c /^op_div(
op_mod exp.c /^op_mod(
op_question exp.c /^op_question(
op_add exp.c /^op_add(
op_sub exp.c /^op_sub(
op_shiftright exp.c /^op_shiftright(
op_shiftleft exp.c /^op_shiftleft(
op_greater exp.c /^op_greater(
op_greatereq exp.c /^op_greatereq(
op_smaller exp.c /^op_smaller(
op_smallereq exp.c /^op_smallereq(
op_eqeq exp.c /^op_eqeq(
op_noteq exp.c /^op_noteq(
op_andand exp.c /^op_andand(
op_oror exp.c /^op_oror(
op_xor exp.c /^op_xor(
op_and exp.c /^op_and(
op_or exp.c /^op_or(
pushchar exp.c /^pushchar(
pushhex exp.c /^pushhex(
pushoct exp.c /^pushoct(
pushdec exp.c /^pushdec(
pushbin exp.c /^pushbin(
pushstr exp.c /^pushstr(
pushsymbol exp.c /^pushsymbol(
main ftohex.c /^main(
exiterr ftohex.c /^exiterr(
convert ftohex.c /^convert(
getwlh ftohex.c /^getwlh(
puth ftohex.c /^puth(
main main.c /^main(
outlistfile main.c /^outlistfile(
tabit main.c /^tabit(
sftos main.c /^sftos(
clearsegs main.c /^clearsegs(
clearrefs main.c /^clearrefs(
cleanup main.c /^cleanup(
while main.c /^    while(
findext main.c /^findext(
rmnode main.c /^rmnode(
parse main.c /^parse(
findmne main.c /^findmne(
v_macro main.c /^v_macro(
addhashtable main.c /^addhashtable(
hash1 main.c /^hash1(
pushinclude main.c /^pushinclude(
asmerr main.c /^asmerr(
zmalloc main.c /^zmalloc(
permalloc main.c /^permalloc(
xbset main.c /^xbset(
bcmp main.c /^bcmp(
v_processor ops.c /^v_processor(
v_mnemonic ops.c /^v_mnemonic(
v_trace ops.c /^v_trace(
v_list ops.c /^v_list(
v_include ops.c /^v_include(
v_seg ops.c /^v_seg(
v_hex ops.c /^v_hex(
gethexdig ops.c /^gethexdig(
v_err ops.c /^v_err(
v_dc ops.c /^v_dc(
v_ds ops.c /^v_ds(
v_org ops.c /^v_org(
v_rorg ops.c /^v_rorg(
v_rend ops.c /^v_rend(
v_align ops.c /^v_align(
v_subroutine ops.c /^v_subroutine(
v_equ ops.c /^v_equ(
v_eqm ops.c /^v_eqm(
v_echo ops.c /^v_echo(
v_set ops.c /^v_set(
v_execmac ops.c /^v_execmac(
v_end ops.c /^v_end(
v_endm ops.c /^v_endm(
v_mexit ops.c /^v_mexit(
v_ifconst ops.c /^v_ifconst(
v_ifnconst ops.c /^v_ifnconst(
v_if ops.c /^v_if(
v_else ops.c /^v_else(
v_endif ops.c /^v_endif(
v_repeat ops.c /^v_repeat(
v_repend ops.c /^v_repend(
generate ops.c /^generate(
closegenerate ops.c /^closegenerate(
genfill ops.c /^genfill(
pushif ops.c /^pushif(
setspecial symbols.c /^setspecial(
findsymbol symbols.c /^findsymbol(
createsymbol symbols.c /^createsymbol(
hash1 symbols.c /^hash1(
programlabel symbols.c /^programlabel(
allocsymbol symbols.c /^allocsymbol(
freesymbol symbols.c /^freesymbol(
freesymbollist symbols.c /^freesymbollist(
\Rogue\Monster\
else
  echo "will not over write src/tags"
fi
if [ `wc -c src/tags | awk '{printf $1}'` -ne 2807 ]
then
echo `wc -c src/tags | awk '{print "Got " $1 ", Expected " 2807}'`
fi
if `test ! -s src/test`
then
echo "writing src/test"
cat > src/test << '\Rogue\Monster\'

run srcc:dasm test.asm -oram:x -f2 -v3

\Rogue\Monster\
else
  echo "will not over write src/test"
fi
if [ `wc -c src/test | awk '{printf $1}'` -ne 41 ]
then
echo `wc -c src/test | awk '{print "Got " $1 ", Expected " 41}'`
fi
if `test ! -s src/mne68705.c`
then
echo "writing src/mne68705.c"
cat > src/mne68705.c << '\Rogue\Monster\'

/*
 *  MNE68705.C
 *
 *  (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 */

#include "asm.h"

#define AFSTD	AF_BYTEADR|AF_BYTEADRX|AF_WORDADR|AF_WORDADRX|AF_0X

extern void v_mnemonic();

MNE Mne68705[] = {
    NULL, v_mnemonic, "adc", 0, AF_IMM8|AFSTD,
	{ 0xA9, 0xB9, 0xE9, 0xC9, 0xD9, 0xF9 },
    NULL, v_mnemonic, "add", 0, AF_IMM8|AFSTD,
	{ 0xAB, 0xBB, 0xEB, 0xCB, 0xDB, 0xFB },
    NULL, v_mnemonic, "and", 0, AF_IMM8|AFSTD,
	{ 0xA4, 0xB4, 0xE4, 0xC4, 0xD4, 0xF4 },
    NULL, v_mnemonic, "asl", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x48, 0x38, 0x68, 0x78 },
    NULL, v_mnemonic, "asla", 0,AF_IMP, { 0x48 },
    NULL, v_mnemonic, "aslx", 0,AF_IMP, { 0x58 },
    NULL, v_mnemonic, "asr", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x47, 0x37, 0x67, 0x77 },
    NULL, v_mnemonic, "asra", 0,AF_IMP, { 0x47 },
    NULL, v_mnemonic, "asrx", 0,AF_IMP, { 0x57 },
    NULL, v_mnemonic, "bcc", 0, AF_REL, { 0x24 },
    NULL, v_mnemonic, "bclr", MF_IMOD,AF_BITMOD, { 0x11 },
    NULL, v_mnemonic, "bcs", 0, AF_REL, { 0x25 },
    NULL, v_mnemonic, "beq", 0, AF_REL, { 0x27 },
    NULL, v_mnemonic, "bhcc", 0,AF_REL, { 0x28 },
    NULL, v_mnemonic, "bhcs", 0,AF_REL, { 0x29 },
    NULL, v_mnemonic, "bhi", 0, AF_REL, { 0x22 },
    NULL, v_mnemonic, "bhs", 0, AF_REL, { 0x24 },
    NULL, v_mnemonic, "bih", 0, AF_REL, { 0x2F },
    NULL, v_mnemonic, "bil", 0, AF_REL, { 0x2E },
    NULL, v_mnemonic, "bit", 0, AF_IMM8|AFSTD,
	{ 0xA5, 0xB5, 0xE5, 0xC5, 0xD5, 0xF5 },
    NULL, v_mnemonic, "blo", 0, AF_REL, { 0x25 },
    NULL, v_mnemonic, "bls", 0, AF_REL, { 0x23 },
    NULL, v_mnemonic, "bmc", 0, AF_REL, { 0x2C },
    NULL, v_mnemonic, "bmi", 0, AF_REL, { 0x2B },
    NULL, v_mnemonic, "bms", 0, AF_REL, { 0x2D },
    NULL, v_mnemonic, "bne", 0, AF_REL, { 0x26 },
    NULL, v_mnemonic, "bpl", 0, AF_REL, { 0x2A },
    NULL, v_mnemonic, "bra", 0, AF_REL, { 0x20 },
    NULL, v_mnemonic, "brn", 0, AF_REL, { 0x21 },
    NULL, v_mnemonic, "brclr", MF_IMOD|MF_REL,   AF_BITBRAMOD, { 0x01 },
    NULL, v_mnemonic, "brset", MF_IMOD|MF_REL,   AF_BITBRAMOD, { 0x00 },
    NULL, v_mnemonic, "bset", MF_IMOD,AF_BITMOD, { 0x10 },
    NULL, v_mnemonic, "bsr", 0, AF_REL, { 0xAD },
    NULL, v_mnemonic, "clc", 0, AF_IMP, { 0x98 },
    NULL, v_mnemonic, "cli", 0, AF_IMP, { 0x9A },
    NULL, v_mnemonic, "clr", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x4F, 0x3F, 0x6F, 0x7F },
    NULL, v_mnemonic, "clra", 0,AF_IMP, { 0x4F },
    NULL, v_mnemonic, "clrx", 0,AF_IMP, { 0x5F },
    NULL, v_mnemonic, "cmp", 0, AF_IMM8|AFSTD,
	{ 0xA1, 0xB1, 0xE1, 0xC1, 0xD1, 0xF1 },
    NULL, v_mnemonic, "com", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x43, 0x33, 0x63, 0x73 },
    NULL, v_mnemonic, "coma", 0,AF_IMP, { 0x43 },
    NULL, v_mnemonic, "comx", 0,AF_IMP, { 0x53 },
    NULL, v_mnemonic, "cpx", 0, AF_IMM8|AFSTD,
	{ 0xA3, 0xB3, 0xE3, 0xC3, 0xD3, 0xF3 },
    NULL, v_mnemonic, "dec", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x4A, 0x3A, 0x6A, 0x7A },
    NULL, v_mnemonic, "deca", 0,AF_IMP, { 0x4A },
    NULL, v_mnemonic, "decx", 0,AF_IMP, { 0x5A },
    NULL, v_mnemonic, "dex", 0, AF_IMP, { 0x5A },
    NULL, v_mnemonic, "eor", 0, AF_IMM8|AFSTD,
	{ 0xA8, 0xB8, 0xE8, 0xC8, 0xD8, 0xF8 },
    NULL, v_mnemonic, "inc", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x4C, 0x3C, 0x6C, 0x7C },
    NULL, v_mnemonic, "inca", 0,AF_IMP, { 0x4C },
    NULL, v_mnemonic, "incx", 0,AF_IMP, { 0x5C },
    NULL, v_mnemonic, "inx", 0, AF_IMP, { 0x5C },
    NULL, v_mnemonic, "jmp", 0, AFSTD,
	{ 0xBC, 0xEC, 0xCC, 0xDC, 0xFC },
    NULL, v_mnemonic, "jsr", 0, AFSTD,
	{ 0xBD, 0xED, 0xCD, 0xDD, 0xFD },
    NULL, v_mnemonic, "lda", 0, AF_IMM8|AFSTD,
	{ 0xA6, 0xB6, 0xE6, 0xC6, 0xD6, 0xF6 },
    NULL, v_mnemonic, "ldx", 0, AF_IMM8|AFSTD,
	{ 0xAE, 0xBE, 0xEE, 0xCE, 0xDE, 0xFE },
    NULL, v_mnemonic, "lsl", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x48, 0x38, 0x68, 0x78 },
    NULL, v_mnemonic, "lsla", 0,AF_IMP, { 0x48 },
    NULL, v_mnemonic, "lslx", 0,AF_IMP, { 0x58 },
    NULL, v_mnemonic, "lsr", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x44, 0x34, 0x64, 0x74 },
    NULL, v_mnemonic, "lsra", 0,AF_IMP, { 0x44 },
    NULL, v_mnemonic, "lsrx", 0,AF_IMP, { 0x54 },
    NULL, v_mnemonic, "neg", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x40, 0x30, 0x60, 0x70 },
    NULL, v_mnemonic, "nega", 0,AF_IMP, { 0x40 },
    NULL, v_mnemonic, "negx", 0,AF_IMP, { 0x50 },
    NULL, v_mnemonic, "nop", 0, AF_IMP, { 0x9D },
    NULL, v_mnemonic, "ora", 0, AF_IMM8|AFSTD,
	{ 0xAA, 0xBA, 0xEA, 0xCA, 0xDA, 0xFA },
    NULL, v_mnemonic, "rol", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x49, 0x39, 0x69, 0x79 },
    NULL, v_mnemonic, "rola", 0,AF_IMP, { 0x49 },
    NULL, v_mnemonic, "rolx", 0,AF_IMP, { 0x59 },
    NULL, v_mnemonic, "ror", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x46, 0x36, 0x66, 0x76 },
    NULL, v_mnemonic, "rora", 0,AF_IMP, { 0x46 },
    NULL, v_mnemonic, "rorx", 0,AF_IMP, { 0x56 },
    NULL, v_mnemonic, "rsp", 0, AF_IMP, { 0x9C },
    NULL, v_mnemonic, "rti", 0, AF_IMP, { 0x80 },
    NULL, v_mnemonic, "rts", 0, AF_IMP, { 0x81 },
    NULL, v_mnemonic, "sbc", 0, AF_IMM8|AFSTD,
	{ 0xA2, 0xB2, 0xE2, 0xC2, 0xD2, 0xF2 },
    NULL, v_mnemonic, "sec", 0, AF_IMP, { 0x99 },
    NULL, v_mnemonic, "sei", 0, AF_IMP, { 0x9B },
    NULL, v_mnemonic, "sta", 0, AFSTD,
	{ 0xB7, 0xE7, 0xC7, 0xD7, 0xF7 },
    NULL, v_mnemonic, "stx", 0, AFSTD,
	{ 0xBF, 0xEF, 0xCF, 0xDF, 0xFF },
    NULL, v_mnemonic, "sub", 0, AF_IMM8|AFSTD,
	{ 0xA0, 0xB0, 0xE0, 0xC0, 0xD0, 0xF0 },
    NULL, v_mnemonic, "swi", 0, AF_IMP, { 0x83 },
    NULL, v_mnemonic, "tax", 0, AF_IMP, { 0x97 },
    NULL, v_mnemonic, "tst", 0, AF_IMP|AF_BYTEADR|AF_BYTEADRX|AF_0X,
	{ 0x4D, 0x3D, 0x6D, 0x7D },
    NULL, v_mnemonic, "tsta", 0,AF_IMP, { 0x4D },
    NULL, v_mnemonic, "tstx", 0,AF_IMP, { 0x5D },
    NULL, v_mnemonic, "txa", 0, AF_IMP, { 0x9F },
    NULL
};

\Rogue\Monster\
else
  echo "will not over write src/mne68705.c"
fi
if [ `wc -c src/mne68705.c | awk '{printf $1}'` -ne 5823 ]
then
echo `wc -c src/mne68705.c | awk '{print "Got " $1 ", Expected " 5823}'`
fi
if `test ! -s src/ftohex.c`
then
echo "writing src/ftohex.c"
cat > src/ftohex.c << '\Rogue\Monster\'

/*
 *  FTOHEX.C
 *
 *  (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 *
 *  FTOHEX format infile [outfile]
 *
 *  format: format used when assembling (asm705/asm65)
 *	    1,2,3	    -generate straight hex file
 *
 *  compilable on an ibm-pc or Amiga  _fmode is for Lattice C on the ibm,
 *  is IGNORED by Aztec C on the Amiga.  Note that INT and CHAR are not
 *  used as ibm's lattice C uses 16 bit ints and unsigned chars.  Change
 *  as needed.	No guarentees for the IBMPC version.
 */

#include <stdio.h>

#ifdef IBM
typedef char ubyte;
typedef unsigned uword;
typedef int void;
#else
typedef unsigned char ubyte;
typedef unsigned short uword;
#endif

#define PERLINE 16

extern long ftell();
extern void fseek();
extern uword getwlh();
extern void  puth();

uword _fmode = 0;

main(ac, av)
ubyte *av[];
short ac;
{
    short format;
    FILE *infile;
    FILE *outfile;

    _fmode = 0x8000;
    if (ac < 3) {
	puts("FTOHEX format infile [outfile]");
	puts("format 1,2, or 3.  3=raw");
	puts("(C)Copyright 1987 by Matthew Dillon, All Rights Reserved");
	exit(1);
    }
    format = atoi(av[1]);
    if (format < 1 || format > 3)
	exiterr("specify infile format 1, 2, or 3");
    infile = fopen(av[2], "r");
    if (infile == NULL)
	exiterr("unable to open input file");
    outfile = (av[3]) ? fopen(av[3], "w") : stdout;
    if (outfile == NULL)
	exiterr("unable to open output file");
    convert(format, infile, outfile);
    fclose(infile);
    fclose(outfile);
}

exiterr(str)
ubyte *str;
{
    fputs(str, stderr);
    fputs("\n", stderr);
    exit(1);
}

/*
 *  Formats:
 *
 *  1:	origin (word:lsb,msb) + data
 *  2:	origin (word:lsb,msb) + length (word:lsb,msb) + data  (repeat)
 *  3:	data
 *
 *  Hex output:
 *
 *  :lloooo00(ll bytes hex code)cc      ll=# of bytes
 *					oooo=origin
 *					cc=invert of checksum all codes
 */

convert(format, in, out)
short format;
FILE *in;
FILE *out;
{
    uword org = 0;
    uword idx;
    long len;
    ubyte buf[256];

    if (format < 3)
	org = getwlh(in);
    if (format == 2) {
	len = getwlh(in);
    } else {
	long begin = ftell(in);
	fseek(in, 0L, 2);
	len = ftell(in) - begin;
	fseek(in, begin, 0);
    }
    for (;;) {
	while (len > 0) {
	    register ubyte chk;
	    register short i;

	    idx = (len > PERLINE) ? PERLINE : len;
	    fread(buf, idx, 1, in);
	    putc(':', out);
	    puth(idx, out);
	    puth(org >> 8, out);
	    puth(org & 0xFF, out);
	    putc('0', out);
	    putc('0', out);
	    chk = idx + (org >> 8) + (org & 0xFF);
	    for (i = 0; i < idx; ++i) {
		chk += buf[i];
		puth(buf[i], out);
	    }
	    puth((ubyte)-chk, out);
	    putc('\r', out);
	    putc('\n', out);
	    len -= idx;
	    org += idx;
	}
	if (format == 2) {
	    org = getwlh(in);
	    if (feof(in))
		break;
	    len = getwlh(in);
	} else {
	    break;
	}
    }
    fprintf(out, ":00000001FF\r\n");
}

uword
getwlh(in)
FILE *in;
{
    uword result;

    result = getc(in);
    result += getc(in) << 8;
    return(result);
}

void
puth(c, out)
ubyte c;
FILE *out;
{
    static ubyte dig[] = { "0123456789ABCDEF" };
    putc(dig[c>>4], out);
    putc(dig[c&15], out);
}

\Rogue\Monster\
else
  echo "will not over write src/ftohex.c"
fi
if [ `wc -c src/ftohex.c | awk '{printf $1}'` -ne 3133 ]
then
echo `wc -c src/ftohex.c | awk '{print "Got " $1 ", Expected " 3133}'`
fi
if `test ! -s src/symbols.c`
then
echo "writing src/symbols.c"
cat > src/symbols.c << '\Rogue\Monster\'

/*
 *  SYMBOLS.C
 *
 *  (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 */

#include "asm.h"

extern uword hash1();

static SYMBOL org;
static SYMBOL special;
static SYMBOL specchk;

void
setspecial(value, flags)
{
    special.value = value;
    special.flags = flags;
}

SYMBOL *
findsymbol(str, len)
ubyte *str;
short len;
{
    register uword h1;
    register SYMBOL *sym;
    ubyte buf[64];
    static SYMBOL org;
    short n;

    if (str[0] == '.') {
	if (len == 1) {
	    if (Csegment->flags & SF_RORG) {
		org.flags = Csegment->rflags & SYM_UNKNOWN;
		org.value = Csegment->rorg;
	    } else {
		org.flags = Csegment->flags & SYM_UNKNOWN;
		org.value = Csegment->org;
	    }
	    return(&org);
	}
	if (len == 2 && str[1] == '.')
	    return(&special);
	if (len == 3 && str[1] == '.' && str[2] == '.') {
	    specchk.flags = 0;
	    specchk.value = CheckSum;
	    return(&specchk);
	}
	sprintf(buf, "%ld", Localindex);
	n = strlen(buf);
	bmov(str, buf+n, len);
	len += n;
	str = buf;
    }
    h1 = hash1(str, len);
    for (sym = SHash[h1]; sym; sym = sym->next) {
	if (sym->namelen == len && bcmp(sym->name, str, len))
	    break;
    }
    return(sym);
}

SYMBOL *
createsymbol(str, len)
ubyte *str;
short len;
{
    register SYMBOL *sym;
    register uword h1;
    ubyte buf[64];

    if (str[0] == '.') {
	short n;
	sprintf(buf, "%ld", Localindex);
	n = strlen(buf);
	bmov(str, buf+n, len);
	len += n;
	str = buf;
    }
    sym = (SYMBOL *)allocsymbol();
    sym->name = permalloc(len+1);
    bmov(str, sym->name, len);        /*  permalloc zero's the array for us */
    sym->namelen = len;
    h1 = hash1(str, len);
    sym->next = SHash[h1];
    sym->flags= SYM_UNKNOWN;
    SHash[h1] = sym;
    return(sym);
}

static uword
hash1(str, len)
register ubyte *str;
register short len;
{
    register uword result = 0;

    while (len--)
	result = (result << 2) ^ *str++;
    return(result & SHASHAND);
}

/*
 *  Label Support Routines
 */

void
programlabel()
{
    register uword len;
    register SYMBOL *sym;
    register SEGMENT *cseg = Csegment;
    register ubyte *str;
    ubyte   rorg = cseg->flags & SF_RORG;
    ubyte   cflags = (rorg) ? cseg->rflags : cseg->flags;
    ulong   pc = (rorg) ? cseg->rorg : cseg->org;

    Plab = cseg->org;
    Pflags = cseg->flags;
    str = Av[0];
    if (*str == 0)
	return;
    len = strlen(str);
    if (str[len-1] == ':')
	--len;

    /*
     *	Redo:	unknown and referenced
     *		referenced and origin not known
     *		known and phase error	(origin known)
     */

    if (sym = findsymbol(str, len)) {
	if ((sym->flags & (SYM_UNKNOWN|SYM_REF)) == (SYM_UNKNOWN|SYM_REF)) {
	    ++Redo;
	    Redo_why |= 1 << 13;
	    if (Xdebug)
		printf("redo 13: '%s' %04x %04x\n", sym->name, sym->flags, cflags);
	} else
	if ((cflags & SYM_UNKNOWN) && (sym->flags & SYM_REF)) {
	    ++Redo;
	    Redo_why |= 1 << 13;
	} else
	if (!(cflags & SYM_UNKNOWN) && !(sym->flags & SYM_UNKNOWN)) {
	    if (pc != sym->value) {
		printf("mismatch %10s %s  pc: %s\n", sym->name, sftos(sym->value, sym->flags), sftos(pc, cflags & 7));
		asmerr(17,0);
		++Redo;
		Redo_why |= 1 << 14;
	    }
	}
    } else {
	sym = createsymbol(str, len);
    }
    sym->value = pc;
    sym->flags = (sym->flags & ~SYM_UNKNOWN) | (cflags & SYM_UNKNOWN);
}

SYMBOL *SymAlloc;

SYMBOL *
allocsymbol()
{
    SYMBOL *sym;

    if (SymAlloc) {
	sym = SymAlloc;
	SymAlloc = SymAlloc->next;
	bzero(sym, sizeof(SYMBOL));
    } else {
	sym = (SYMBOL *)permalloc(sizeof(SYMBOL));
    }
    return(sym);
}

void
freesymbol(sym)
SYMBOL *sym;
{
    sym->next = SymAlloc;
    SymAlloc = sym;
}

void
freesymbollist(sym)
SYMBOL *sym;
{
    register SYMBOL *next;

    while (sym) {
	next = sym->next;
	sym->next = SymAlloc;
	if (sym->flags & SYM_STRING)
	    free(sym->string);
	SymAlloc = sym;
	sym = next;
    }
}

\Rogue\Monster\
else
  echo "will not over write src/symbols.c"
fi
if [ `wc -c src/symbols.c | awk '{printf $1}'` -ne 3830 ]
then
echo `wc -c src/symbols.c | awk '{print "Got " $1 ", Expected " 3830}'`
fi
echo "Finished archive 3 of 3"
# if you want to concatenate archives, remove anything after this line
exit
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.