[net.sources] 6502 Assembler

brownc@utah-cs.UUCP (Eric C. Brown) (05/03/85)

# Due to overwhelming demand, (15 requests in 3 days), here is the 6502
# assembler in C:

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	assmtest
#	assmtest.l
#	makefile
#	user.nr
# This archive created: Tue Apr  2 14:21:42 1985
# By:	James Van Ornum (AT&T-Bell Laboratories)
export PATH; PATH=/bin:$PATH
if test -f 'assmtest'
then
	echo shar: over-writing existing file "'assmtest'"
fi
cat << \SHAR_EOF > 'assmtest'
;******************************************
; Test file for the 6502 assembler - as6502
; assemble as
;     as6502 -nisv assmtest
; and compare output with assmtest.l
;******************************************
;; comment treatment
;******************************************
aa = $10; ';' immediately after the '0'
B = $20 space to comment subfield
C = $30	tab to comment subfield
DEFGHIjkl = $FFEE
D =DEFGHIjkl
;******************************************
; Number formats
;******************************************
start *= $4 ; location counter adjust
 .byte %0101 ; binary number
 .byte 022,@22 ; octal numbers - two forms
 .byte 22 ; decimal number
 .byte $22,$ff,$FF ; hex - upper/lower case
 .byte 'a,'b ; single ASCII characters
;******************************************
;; ASCII character string
;******************************************
 .byte "abcd\t\n",0 ;   tab and new line escaped
;******************************************
; Operation checks
;******************************************
 .word aa+B ; addition
 .word aa-B ; subtraction
 .word aa*B ; multiplication
 .word B/aa ; division
 .word C%B ; modulo
 .word B^C ; exclusive OR
 .word ~C ; one's complement
 .word B&C ; logical AND
 .word aa|B ; logical OR
 .word <D ; low byte
 .word >D ; high byte
 .word * ; current location
 .word aa,B,C
 .word B*[aa+C] ; one level of parenthesis
 .dbyt D ; high byte-low byte word
 .word D/256,D%256
;******************************************
; Addressing Mode Check
;******************************************
 *=$0100
 lda =aa ; immediate addressing
 lda #aa ; immediate addressing, alternate
 lda D ; direct addessing
 LDA aa ; page zero addressing, aa < 256
a1 = 512
a2 = 500
 lda a1-a2 ; also page zero
 asl A ; accumulator addressing
 AsL a ; accumulator addressing also
 brk ; implied addressing
 lda (aa,X) ; indirect,X addressing
 lda (aa),Y ; indirect,Y addressing
 lda aa,X ; zero page,X addressing
 lda D,X ; absolute,X addressing
 lda D,Y ; absolute,Y addressing
 bcc *-$10 ; relative addressing
 jmp (D) ; indirect addressing
 ldx aa,Y ; zero page,Y addressing
 ldx aa,y ; alternate index name
 .nlst
;******************************************
; opcode check
;******************************************
 adc =01
 and =01
 asl A
 bcc *+2
 bcs *+2
 beq *+2
 bit $01
 bmi *+2
 bne *+2
 bpl *+2
 brk
 bvc *+2
 bvs *+2
 clc
 cld
 cli
 clv
 cmp =01
 cpx =01
 cpy =01
 dec $01
 dex
 dey
 eor =01
 inc $01
 inx
 iny
 jmp *+3
 jsr *+3
 lda =01
 ldx =01
 ldy =01
 lsr A
 nop
 ora =01
 pha
 php
 pla
 plp
 rol A
 ror A
 rti
 rts
 sbc =01
 sec
 sed
 sei
 sta $01
 stx $01
 sty $01
 tax
 tay
 tsx
 txa
 txs
 tya
SHAR_EOF
if test -f 'assmtest.l'
then
	echo shar: over-writing existing file "'assmtest.l'"
fi
cat << \SHAR_EOF > 'assmtest.l'
as6502 - version 4.1 - 11/5/84 - JHV
   1                   ;******************************************
   2                   ; Test file for the 6502 assembler - as6502
   3                   ; assemble as
   4                   ;     as6502 -nisv assmtest
   5                   ; and compare output with assmtest.l
   6                   ;******************************************
   7                   ;                      ; comment treatment
   8                   ;******************************************
   9         0010      aa      =     $10      ; ';' immediately after the '0'
  10         0020      B       =     $20      space to comment subfield
  11         0030      C       =     $30      tab to comment subfield
  12         FFEE      DEFGHIjkl =   $FFEE
  13         FFEE      D       =DEFGHIjkl
  14                   ;******************************************
  15                   ; Number formats
  16                   ;******************************************
  17         0004      start   *=    $4        ; location counter adjust
  18  0004   05                .byte %0101     ; binary number
  19  0005   12 12             .byte 022,@22   ; octal numbers - two forms
  20  0007   16                .byte 22        ; decimal number
  21  0008   22 FF FF          .byte $22,$ff,$FF  ; hex - upper/lower case
  22  000B   61 62             .byte 'a,'b     ; single ASCII characters
  23                   ;******************************************
  24                   ;                      ; ASCII character string
  25                   ;******************************************
  26  000D   61 62 63          .byte "abcd\t\n",0  ;   tab and new line escaped
      0010   64 09 0A  
      0013   00        
  27                   ;******************************************
  28                   ; Operation checks
  29                   ;******************************************
  30  0014   30 00             .word aa+B      ; addition
  31  0016   F0 FF             .word aa-B      ; subtraction
  32  0018   00 02             .word aa*B      ; multiplication
  33  001A   02 00             .word B/aa      ; division
  34  001C   10 00             .word C%B       ; modulo
  35  001E   10 00             .word B^C       ; exclusive OR
  36  0020   CF FF             .word ~C        ; one's complement
  37  0022   20 00             .word B&C       ; logical AND
  38  0024   30 00             .word aa|B      ; logical OR
  39  0026   EE 00             .word <D        ; low byte
  40  0028   FF 00             .word >D        ; high byte
  41  002A   2A 00             .word *         ; current location
  42  002C   10 00             .word aa,B,C
      002E   20 00     
      0030   30 00     
  43  0032   00 08             .word B*[aa+C]  ; one level of parenthesis
  44  0034   FF EE             .dbyt D         ; high byte-low byte word
  45  0036   FF 00             .word D/256,D%256
      0038   EE 00     
  46                   ;******************************************
  47                   ; Addressing Mode Check
  48                   ;******************************************
  49         0100              *=$0100
  50  0100   A9 10             lda   =aa       ; immediate addressing
  51  0102   A9 10             lda   #aa       ; immediate addressing, alternate
  52  0104   AD EE FF          lda   D         ; direct addessing
  53  0107   A5 10             LDA   aa        ; page zero addressing, aa < 256
  54         0200      a1      =     512
  55         01F4      a2      =     500
  56  0109   A5 0C             lda   a1-a2     ; also page zero
  57  010B   0A                asl   A         ; accumulator addressing
  58  010C   0A                AsL   a         ; accumulator addressing also
  59  010D   00                brk            ; implied addressing
  60  010E   A1 10             lda   (aa,X)    ; indirect,X addressing
  61  0110   B1 10             lda   (aa),Y    ; indirect,Y addressing
  62  0112   B5 10             lda   aa,X      ; zero page,X addressing
  63  0114   BD EE FF          lda   D,X       ; absolute,X addressing
  64  0117   B9 EE FF          lda   D,Y       ; absolute,Y addressing
  65  011A   90 EE             bcc   *-$10     ; relative addressing
  66  011C   6C EE FF          jmp   (D)       ; indirect addressing
  67  011F   B6 10             ldx   aa,Y      ; zero page,Y addressing
  68  0121   B6 10             ldx   aa,y      ; alternate index name
  70                   ;******************************************
  71                   ; opcode check
  72                   ;******************************************
  73  0123   69 01             adc   =01
  74  0125   29 01             and   =01
  75  0127   0A                asl   A
  76  0128   90 00             bcc   *+2
  77  012A   B0 00             bcs   *+2
  78  012C   F0 00             beq   *+2
  79  012E   24 01             bit   $01
  80  0130   30 00             bmi   *+2
  81  0132   D0 00             bne   *+2
  82  0134   10 00             bpl   *+2
  83  0136   00                brk
  84  0137   50 00             bvc   *+2
  85  0139   70 00             bvs   *+2
  86  013B   18                clc
  87  013C   D8                cld
  88  013D   58                cli
  89  013E   B8                clv
  90  013F   C9 01             cmp   =01
  91  0141   E0 01             cpx   =01
  92  0143   C0 01             cpy   =01
  93  0145   C6 01             dec   $01
  94  0147   CA                dex
  95  0148   88                dey
  96  0149   49 01             eor   =01
  97  014B   E6 01             inc   $01
  98  014D   E8                inx
  99  014E   C8                iny
 100  014F   4C 52 01          jmp   *+3
 101  0152   20 55 01          jsr   *+3
 102  0155   A9 01             lda   =01
 103  0157   A2 01             ldx   =01
 104  0159   A0 01             ldy   =01
 105  015B   4A                lsr   A
 106  015C   EA                nop
 107  015D   09 01             ora   =01
 108  015F   48                pha
 109  0160   08                php
 110  0161   68                pla
 111  0162   28                plp
 112  0163   2A                rol   A
 113  0164   6A                ror   A
 114  0165   40                rti
 115  0166   60                rts
 116  0167   E9 01             sbc   =01
 117  0169   38                sec
 118  016A   F8                sed
 119  016B   78                sei
 120  016C   85 01             sta   $01
 121  016E   86 01             stx   $01
 122  0170   84 01             sty   $01
 123  0172   AA                tax
 124  0173   A8                tay
 125  0174   BA                tsx
 126  0175   8A                txa
 127  0176   9A                txs
 128  0177   98                tya

aa                  	10:00	0010
B                   	20:00	0020
C                   	30:00	0030
DEFGHIjkl           	EE:FF	FFEE
D                   	EE:FF	FFEE
start               	04:00	0004
a1                  	00:02	0200
a2                  	F4:01	01F4
SHAR_EOF
if test -f 'makefile'
then
	echo shar: over-writing existing file "'makefile'"
fi
cat << \SHAR_EOF > 'makefile'
as6502:		assm0.o assm1.o assm2.o assm3.o
		cc -s -i assm0.o assm1.o assm2.o assm3.o -o as6502

assm0.o:	assm.d1 assm.d2 assm0.c
		cc -c -O assm0.c

assm1.o:	assm.d1 assm.d2 assm1.c
		cc -c -O assm1.c

assm2.o:	assm.d1 assm.d2	assm2.c
		cc -c -O assm2.c

assm3.o:	assm.d1 assm.d2 assm3.c
		cc -c -O assm3.c

check:		assmtest.l

assmtest.l:	as6502
		as6502 -nisv assmtest > temp
		touch assmtest.l
		diff assmtest.l temp

manuals:	as6502.l user.l

as6502.l:	as6502.1
		man -d as6502.1 > as6502.l

user.l:		user.nr
		nroff user.nr > user.l

clean:
		rm assm0.o assm1.o assm2.o assm3.o temp as6502.l user.l
SHAR_EOF
if test -f 'user.nr'
then
	echo shar: over-writing existing file "'user.nr'"
fi
cat << \SHAR_EOF > 'user.nr'
.de hd
'sp 3
.tl ''\fBas6502 User Notes\fR'Page %'
'sp 2
..
.de fo
'bp
..
.wh 0 hd
.wh -3 fo
.br
\fBSOURCE LINE FORMAT\fR:
.ti 0.5i
.sp 1
<label> <operation> <operand> <comment>
.sp 1
Each field is terminated by one or more spaces, a tab or a ';' (which
begins the comment field immediately).
.sp
\fBLABEL FIELD\fR:
.sp 1
If first character is ';', entire line is a comment.
If first character is space, label field is null.
Labels are alphanumeric strings beginning
with 'a' through 'z', 'A' through 'Z',
underscore or period followed by any of the above
characters or '0' through '9'.
Currently, labels are limited to 19 characters.
A, X, Y, a, x and y are reserved labels.
.sp
\fBOPERATION FIELD\fR:
.sp 1
Upper and lower case letters are equivalent.
Machine operation mnemonics are:
.in 0.5i
.nf
.sp 1
ADC     BMI     CLD     DEX     JSR     PHA     RTS     STY
AND     BNE     CLI     DEY     LDA     PHP     SBC     TAX
ASL     BPL     CLV     EOR     LDX     PLA     SEC     TAY
BCC     BRK     CMP     INC     LDY     PLP     SED     TSX
BCS     BVC     CPX     INX     LSR     ROL     SEI     TXA
BEQ     BVS     CPY     INY     NOP     ROR     STA     TXS
BIT     CLC     DEC     JMP     ORA     RTI     STX     TYA
.in 0
.fi
.sp 1
Pseudo operation mnemonics are:
.in 1.2i
.ti 0.5i
.sp 1
=      equate label name to operand field value
(space is not needed to terminate this operation).
.ti 0.5i
*=     set location counter to operand field value
(space is not needed to terminate this operation).
.ti 0.5i
.tr*.
*WORD  assign 16 bit value of operand field to next
two locations; low byte of value first, then high byte.
.ti 0.5i
*DBYT  assign 16 bit value of operand field to next
two locations; high byte of value first, then low byte.
.ti 0.5i
*BYTE  assign 8 bit value of operand field to next
location.
.ti 0.5i
*NLST  turn listing mode off (this source
line is not listed).
.ti 0.5i
*LIST  turn listing mode on (normal mode) (this
source line is not listed).
.tr**
.in 0
.sp 1
\fBOPERAND FIELD\fR:
.sp 1
Operand field expressions use infix notation and are evaluated strictly
from left to right.
No imbedded spaces are permitted.
.sp 1
Operand field terms include labels and numbers.
Asterisk (*) is the label for the location counter value.
Numbers are binary, octal, decimal, hexadecimal or ASCII.
Number type is indicated by the first character of the number string as follows:
.nf
.in 0.5i
.sp 1
%       binary prefix
@ or 0  octal prefix
1 - 9   decimal by default (prefix is part of number)
$       hexadecimal prefix
.tr,'
,       ASCII character prefix
.tr,,
"       ASCII character string prefix and suffix; in the
        string, \\t is a tab character, \\n is a new line.
.in 0
.fi
.sp 1
Operand field operations and the corresponding symbols are:
.in 0.5i
.nf
.sp 1
+       addition
-       subtraction
/       division
*       multiplication
%       modulo (remainder after integer division)
^       logical exclusive OR
&       logical AND
|       logical OR
<       low byte
>       high byte
.in 0
.fi
.sp 1
\fBERROR MESSAGES\fR:
.in 0.5i
.nf
.sp 1
Invalid operation code
Invalid argument count (when as6502 was invoked)
Open error for file
Creat error for object file 6502.out
Close error
Close error (6502.out)
Symbol table full
Label multiply defined
Sync error (pass 1 symbol value not equal pass 2 symbol value)
Invalid branch address
Operand field missing
Invalid addressing mode
Operand field size error
Undefined symbol in operand field
Invalid operand field
.fi
.in 0
.sp 1
\fBINVOKING as6502\fR:
.sp 1
.ti 0.5i
as6502 {-ilnos} <source files descriptions>
.sp 1
Options:
.in 0.5i
.nf
.sp 1
-i   ignore any .nlst pseudo operations
-l   list errors only
-n   print addresses as <high byte><low byte>,
     rather than as <low byte>:<high byte>.
-o   generate ASCII object output in file 6502.out,
     format is
          ;<address lo><address hi><data>
-s   print symbol table at end of listing

                     J. H. Van Ornum  11/5/84
SHAR_EOF
#	End of shell archive
exit 0

brownc@utah-cs.UUCP (Eric C. Brown) (05/03/85)

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	as6502.1
#	assm.d1
#	assm.d2
#	assm0.c
#	assm1.c
# This archive created: Tue Apr  2 14:21:10 1985
# By:	James Van Ornum (AT&T-Bell Laboratories)
export PATH; PATH=/bin:$PATH
if test -f 'as6502.1'
then
	echo shar: over-writing existing file "'as6502.1'"
fi
cat << \SHAR_EOF > 'as6502.1'
.TH AS6502 1 11/5/84 
.SH NAME
as6502 \- assembler for MOS Technology 650X microprocessors
.SH SYNOPSIS
.B as6502
[ option ] file ...
.SH DESCRIPTION
.I As6502
assembles the named files and produces
a listing on the standard output.
Available options are:
.TP 4
.B \-i
ignore .nlst pseudo ops in the source file.
.TP
.B \-l
produce only an error listing on the standard output.
.TP
.B \-n
print address in normal <high byte><low byte> format,
rather than split <low byte>:<high byte> format.
.TP
.B \-o
generate the ASCII object file
.B "6502.out."
The per-line format of that file is:
.br
    ;<address low byte><address high byte><data>...
.TP
.B \-s
print symbol table at the end of the assembly listing.
.TP
Symbol conventions:
.br
.tr ~|
Up to 19 alphanumeric (a-z ~ A-Z ~ 0-9 ~ . ~ _) characters,
.tr ~~
with initial character non-numeric.
.sp
Asterisk (*) is symbolic name of the location counter.
.TP
Op code mnemonics (upper and/or lower case):
.br
ADC   BIT   BVS   CPX   INC   LDX   PHP   RTI   SEI  TAY
.br
AND   BMI   CLC   CPY   INX   LDY   PLA   RTS   STA  TSX
.br
ASL   BNE   CLD   DEC   INY   LSR   PLP   SBC   STX  TXA
.br
BCC   BPL   CLI   DEX   JMP   NOP   ROL   SEC   STY  TXS
.br
BCS   BRK   CLV   DEY   JSR   ORA   ROR   SED   TAX  TYA
.br
BEQ   BVC   CMP   EOR   LDA   PHA
.TP
Pseudo op mnemonics:
.br
=      equate label to operand value.
.br
*=     equate location counter to operand value.
.br
 .WORD  assign 16 bit operand value to next 2 locations.
.br
 .DBYT  assign 16 bit value to next 2 locations, reverse.
.br
 .BYTE  assign 8 bit operand value to next location.
.br
 .NLST  turn listing mode off.
.br
 .LIST  turn listing mode on.
.TP
Constant types:
.br
%       binary number prefix.
.br
@ or 0  octal number prefix.
.br
$       hexadecimal number prefix.
.br
 '       ASCII character prefix.
.br
 "       ASCII character string prefix and suffix.
.br
default (leading digit 1 through 9)  decimal number.
.TP
Operand field operators:
.br
+     addition               ^     logical exclusive OR
.br
-     subtraction            ~     logical 1's complement
.br
/     integer division       $     logical AND
.br
.tr ||
*     multiplication         |     logical OR
.br
%     modulo                 <     low byte
.br
                             >     high byte
.SH FILES
.PD 0
.TP
/BIN/as6502   the assembler
.TP
6502.out      object (with -o option)
.SH "SEE ALSO"
.TP
J. H. Van Ornum, "as6502 User Notes"
.SH DIAGNOSTICS
.in 0
File handling diagnostics:
.in 15
.ti 5
Invalid argument count - as6502 invoked without a source file or
with too many source files.
.ti 5
Open error for file <name> - as6502 cannot open source file.
.ti 5
Create error (6502.out) - as6502 cannot create object file.
.ti 5
Close error - as6502 cannot close the source file.
.ti 5
Close error (6502.out) - as6502 cannot close object file.
.in 0
Assembly error diagnostics:
.in 15
.ti 5
Symbol table full - symbol table overflowed allotted space.
Number of symbols is a function of symbol sizes.
.ti 5
Label multiply defined - symbol defined more than once.
.ti 5
Sync error - the pass 2 value of symbol in the label field is different
than the pass 1 value.
.ti 5
Invalid operation code - op code mnemonic is invalid.
.ti 5
Operand field missing - the op code mnemonic requires an operand, and none was
found.
.ti 5
Invalid operand field - operand field contains an operator which is not
recognized by as6502.
.ti 5
Invalid branch address - branch instruction to a location which is out of range.
.ti 5
Invalid addressing mode - tried to use an addressing mode which is not
available to the operation code.
.ti 5
Operand field size error - operand is larger than hex FF.
.ti 5
Undefined symbol in operand field - a symbol in the operand field never
appeared in the label field.
.SH BUGS
SHAR_EOF
if test -f 'assm.d1'
then
	echo shar: over-writing existing file "'assm.d1'"
fi
cat << \SHAR_EOF > 'assm.d1'
#define LAST_CH_POS	132
#define SFIELD	23
#define STABSZ	6000
#define SBOLSZ	20

/*
 * symbol flags
 */
#define DEFZRO	2	/* defined - page zero address	*/
#define MDEF	3	/* multiply defined		*/
#define UNDEF	1	/* undefined - may be zero page */
#define DEFABS	4	/* defined - two byte address	*/
#define UNDEFAB 5	/* undefined - two byte address */

/*
 * operation code flags
 */
#define PSEUDO	0x6000
#define CLASS1	0x2000
#define CLASS2	0x4000
#define IMM1	0x1000		/* opval + 0x00	2 byte	*/
#define IMM2	0x0800		/* opval + 0x08	2 byte	*/
#define ABS	0x0400		/* opval + 0x0C	3 byte	*/
#define ZER	0x0200		/* opval + 0x04	2 byte	*/
#define INDX	0x0100		/* opval + 0x00	2 byte	*/
#define ABSY2	0x0080		/* opval + 0x1C	3 byte	*/
#define INDY	0x0040		/* opval + 0x10	2 byte	*/
#define ZERX	0x0020		/* opval + 0x14	2 byte	*/
#define ABSX	0x0010		/* opval + 0x1C	3 byte	*/
#define ABSY	0x0008		/* opval + 0x18	3 byte	*/
#define ACC	0x0004		/* opval + 0x08	1 byte	*/
#define IND	0x0002		/* opval + 0x2C	3 byte	*/
#define ZERY	0x0001		/* opval + 0x14	2 byte	*/

/*
 * pass flags
 */
#define FIRST_PASS	0
#define LAST_PASS	1
#define DONE		2
SHAR_EOF
if test -f 'assm.d2'
then
	echo shar: over-writing existing file "'assm.d2'"
fi
cat << \SHAR_EOF > 'assm.d2'
extern	FILE	*optr;
extern	FILE	*iptr;
extern	int	dflag;		/* debug flag */
extern	int	errcnt;		/* error counter */
extern	int	hash_tbl[];	/* pointers to starting links in symtab */
extern	char	hex[];		/* hexadecimal character buffer */
extern	int	iflag;		/* ignore .nlst flag */
extern	int	lablptr;	/* label pointer into symbol table */
extern	int	lflag;		/* disable listing flag */
extern	int	loccnt;		/* location counter	*/
extern	int	nflag;		/* normal/split address mode */
extern	int	nxt_free;	/* next free location in symtab */
extern	int	objcnt;		/* object byte counter */
extern	int	oflag;		/* object output flag */
extern	int	opflg;		/* operation code flags */
extern	int	opval;		/* operation code value */
extern	int	pass;		/* pass counter		*/
extern	char	prlnbuf[];	/* print line buffer	*/
extern	int	sflag;		/* symbol table output flag */
extern	int	slnum;		/* source line number counter */
extern	char	symtab[];	/* symbol table		*/
extern	char	symbol[];	/* temporary symbol storage	*/
extern	int	udtype;		/* undefined symbol type	*/
extern	int	undef;		/* undefined symbol in expression flg  */
extern	int	value;		/* operand field value */
extern	char	zpref;		/* zero page reference flag	*/
SHAR_EOF
if test -f 'assm0.c'
then
	echo shar: over-writing existing file "'assm0.c'"
fi
cat << \SHAR_EOF > 'assm0.c'
#include "stdio.h"
#include "assm.d1"

/*  Assembler for the MOS Technology 650X series of microprocessors
 *  Written by J. H. Van Ornum (201) 949-1781
 *		AT&T Bell Laboratories
 *		 Holmdel, NJ
 */

FILE	*optr;
FILE	*iptr;
int	dflag;			/* debug flag */
int	errcnt;			/* error counter */
int	hash_tbl[128];		/* pointers to starting links in symtab */
char	hex[5];			/* hexadecimal character buffer */
int	iflag;			/* ignore .nlst flag */
int	lablptr;		/* label pointer into symbol table */
int	lflag;			/* disable listing flag */
int	loccnt;			/* location counter	*/
int	nflag;			/* normal/split address mode */
int	nxt_free;		/* next free location in symtab */
int	objcnt;			/* object byte counter */
int	oflag;			/* object output flag */
int	opflg;			/* operation code flags */
int	opval;			/* operation code value */
int	pass;			/* pass counter		*/
char	prlnbuf[LAST_CH_POS+1]; /* print line buffer	*/
int	sflag;			/* symbol table output flag */
int	slnum;			/* source line number counter */
char	symtab[STABSZ];		/* symbol table		*/
				/* struct sym_tab		*/
				/* {	char	size;		*/
				/*	char	chars[size];	*/
				/*	char	flag;		*/
				/*	int	value;		*/
				/*	int	next_pointer	*/
				/* }				*/
char	symbol[SBOLSZ];		/* temporary symbol storage	*/
int	udtype;			/* undefined symbol type	*/
int	undef;			/* undefined symbol in expression flg  */
int	value;			/* operand field value */
char	zpref;			/* zero page reference flag	*/


#define A	0x20)+('A'&0x1f))
#define B	0x20)+('B'&0x1f))
#define C	0x20)+('C'&0x1f))
#define D	0x20)+('D'&0x1f))
#define E	0x20)+('E'&0x1f))
#define F	0x20)+('F'&0x1f))
#define G	0x20)+('G'&0x1f))
#define H	0x20)+('H'&0x1f))
#define I	0x20)+('I'&0x1f))
#define J	0x20)+('J'&0x1f))
#define K	0x20)+('K'&0x1f))
#define L	0x20)+('L'&0x1f))
#define M	0x20)+('M'&0x1f))
#define N	0x20)+('N'&0x1f))
#define O	0x20)+('O'&0x1f))
#define P	0x20)+('P'&0x1f))
#define Q	0x20)+('Q'&0x1f))
#define R	0x20)+('R'&0x1f))
#define S	0x20)+('S'&0x1f))
#define T	0x20)+('T'&0x1f))
#define U	0x20)+('U'&0x1f))
#define V	0x20)+('V'&0x1f))
#define W	0x20)+('W'&0x1f))
#define X	0x20)+('X'&0x1f))
#define Y	0x20)+('Y'&0x1f))
#define Z	0x20)+('Z'&0x1f))

#define OPSIZE	63

int	optab[]	=		/* nmemonic  operation code table	*/
{				/* '.' = 31, '*' = 30, '=' = 29		*/
	((0*0x20)+(29)),PSEUDO,1,
	((((0*0x20)+(30))*0x20)+(29)),PSEUDO,3,
	((((((0*A*D*C,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x61,
	((((((0*A*N*D,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x21,
	((((((0*A*S*L,ABS|ZER|ZERX|ABSX|ACC,0x02,
	((((((0*B*C*C,CLASS2,0x90,
	((((((0*B*C*S,CLASS2,0xb0,
	((((((0*B*E*Q,CLASS2,0xf0,
	((((((0*B*I*T,ABS|ZER,0x20,
	((((((0*B*M*I,CLASS2,0x30,
	((((((0*B*N*E,CLASS2,0xd0,
	((((((0*B*P*L,CLASS2,0x10,
	((((((0*B*R*K,CLASS1,0x00,
	((((((0*B*V*C,CLASS2,0x50,
	((((((0*B*V*S,CLASS2,0x70,
	((((((0*C*L*C,CLASS1,0x18,
	((((((0*C*L*D,CLASS1,0xd8,
	((((((0*C*L*I,CLASS1,0x58,
	((((((0*C*L*V,CLASS1,0xb8,
	((((((0*C*M*P,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0xc1,
	((((((0*C*P*X,IMM1|ABS|ZER,0xe0,
	((((((0*C*P*Y,IMM1|ABS|ZER,0xc0,
	((((((0*D*E*C,ABS|ZER|ZERX|ABSX,0xc2,
	((((((0*D*E*X,CLASS1,0xca,
	((((((0*D*E*Y,CLASS1,0x88,
	((((((0*E*O*R,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x41,
	((((((0*I*N*C,ABS|ZER|ZERX|ABSX,0xe2,
	((((((0*I*N*X,CLASS1,0xe8,
	((((((0*I*N*Y,CLASS1,0xc8,
	((((((0*J*M*P,ABS|IND,0x40,
	((((((0*J*S*R,ABS,0x14,
	((((((0*L*D*A,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0xa1,
	((((((0*L*D*X,IMM1|ABS|ZER|ABSY2|ZERY,0xa2,
	((((((0*L*D*Y,IMM1|ABS|ZER|ABSX|ZERX,0xa0,
	((((((0*L*S*R,ABS|ZER|ZERX|ABSX|ACC,0x42,
	((((((0*N*O*P,CLASS1,0xea,
	((((((0*O*R*A,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x01,
	((((((0*P*H*A,CLASS1,0x48,
	((((((0*P*H*P,CLASS1,0x08,
	((((((0*P*L*A,CLASS1,0x68,
	((((((0*P*L*P,CLASS1,0x28,
	((((((0*R*O*L,ABS|ZER|ZERX|ABSX|ACC,0x22,
	((((((0*R*O*R,ABS|ZER|ZERX|ABSX|ACC,0x62,
	((((((0*R*T*I,CLASS1,0x40,
	((((((0*R*T*S,CLASS1,0x60,
	((((((0*S*B*C,IMM2|ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0xe1,
	((((((0*S*E*C,CLASS1,0x38,
	((((((0*S*E*D,CLASS1,0xf8,
	((((((0*S*E*I,CLASS1,0x78,
	((((((0*S*T*A,ABS|ZER|INDX|INDY|ZERX|ABSX|ABSY,0x81,
	((((((0*S*T*X,ABS|ZER|ZERY,0x82,
	((((((0*S*T*Y,ABS|ZER|ZERX,0x80,
	((((((0*T*A*X,CLASS1,0xaa,
	((((((0*T*A*Y,CLASS1,0xa8,
	((((((0*T*S*X,CLASS1,0xba,
	((((((0*T*X*A,CLASS1,0x8a,
	((((((0*T*X*S,CLASS1,0x9a,
	((((((0*T*Y*A,CLASS1,0x98,
	((((((0*0x20)+(31))*W*O^((((0*R*D,PSEUDO,2,	/* 0x7cab */
	((((((0*0x20)+(31))*B*Y^((((0*T*E,PSEUDO,0,	/* 0x7edc */
	((((((0*0x20)+(31))*D*B^((((0*Y*T,PSEUDO,6,	/* 0x7fb6 */
	((((((0*0x20)+(31))*N*L^((((0*S*T,PSEUDO,5,	/* 0x7fb8 */
	((((((0*0x20)+(31))*L*I^((((0*S*T,PSEUDO,4,	/* 0x7ffd */
	0x7fff,0,0,
	0x7fff,0,0
};

int	step[] =
{
	3*((OPSIZE+1)/2),
	3*((((OPSIZE+1)/2)+1)/2),
	3*((((((OPSIZE+1)/2)+1)/2)+1)/2),
	3*((((((((OPSIZE+1)/2)+1)/2)+1)/2)+1)/2),
	3*(2),
	3*(1),
	0
};
SHAR_EOF
if test -f 'assm1.c'
then
	echo shar: over-writing existing file "'assm1.c'"
fi
cat << \SHAR_EOF > 'assm1.c'
#include "stdio.h"
#include "assm.d1"
#include "assm.d2"

#define CPMEOF EOF

/*
 *  Two changes to version 1.4 have been made to "port" as6502 to CP/M(tm).
 *  A "tolower()" function call was add to the command line processing
 *  code to (re)map the command line arguments to lower case (CP/M
 *  converts all command line arguments to upper case).  The readline()
 *  function has code added to "ignore" the '\r' character (CP/M includes
 *  the \r character along with \n).
 *
 *  Also, the ability to process multiple files on the command line has been
 *  added.  Now one can do, for example:
 *
 *	as6502 -nisvo header.file source.file data.file ...
 *
 *    George V. Wilder
 *	IX 1A-360 x1937
 *	ihuxp!gvw1
 */

main(argc, argv)
   int	argc;
   char *argv[];
{
	char	c;
	int	cnt;
	int	i;
	int	ac;
	char	**av;

	while (--argc > 0 && (*++argv)[0] == '-') {
		for (i = 1; (c = tolower((*argv)[i])) != '\0'; i++) {
			if (c == 'd')		/* debug flag */
				dflag++;
			if (c == 'i')		/* ignore .nlst flag */
				iflag++;
			if (c == 'l')		/* disable listing flag */
				lflag--;
			if (c == 'n')		/* normal/split address mode */
				nflag++;
			if (c == 'o')		/* object output flag */
				oflag++;
			if (c == 's')		/* list symbol table flag */
				sflag++;
			if (c == 'v')		/* print assembler version */
				fprintf(stdout, "as6502 - version 4.1b - 11/22/84 - JHV [gvw]\n");
		}
	}
	ac = argc;
	av = argv;
	pass = FIRST_PASS;
	for (i = 0; i < 128; i++)
		hash_tbl[i] = -1;
	errcnt = loccnt = slnum = 0;
	while (pass != DONE) {
		initialize(ac, av, argc);
		if(pass == LAST_PASS && ac == argc)
			errcnt = loccnt = slnum = 0;
		while (readline() != -1)
			assemble();
		if (errcnt != 0) {
			pass = DONE;
			fprintf(stderr, "Terminated with error counter = %d\n", errcnt);
		}
		switch (pass) {
		case FIRST_PASS:
			--ac;
			++av;
			if(ac == 0) {
				pass = LAST_PASS;
				if (lflag == 0)
					lflag++;
				ac = argc;
				av = argv;
			}
			break;
		case LAST_PASS:
			--ac;
			++av;
			if(ac == 0) {
				pass = DONE;
				if (sflag != 0)
					stprnt();
			}
		}
		wrapup();
		if ((dflag != 0) && (pass == LAST_PASS)) {
			fprintf(stdout, "nxt_free = %d\n", nxt_free);
			cnt = 0;
			for (i = 0; i < 128; i++)
				if (hash_tbl[i] == -1)
					cnt++;
			fprintf(stdout, "%d unused hash table pointers out of 128\n", cnt);
		}
	}
	return(0);
}

/*****************************************************************************/

/* initialize opens files */

initialize(ac, av, argc)
   int	ac;
   char *av[];
   int  argc;
{

	if (ac == 0) {
		fprintf(stderr, "Invalid argument count (%d).\n", argc);
		exit(1);
	}
	if ((iptr = fopen(*av, "r")) == NULL) {
		fprintf(stderr, "Open error for file '%s'.\n", *av);
		exit(1);
	}
	if ((pass == LAST_PASS) && (oflag != 0) && ac == argc) {
		if ((optr = fopen("6502.out", "w")) == NULL) {
			fprintf(stderr, "Create error for object file 6502.out.\n");
			exit(1);
		}
	}
}

/* readline reads and formats an input line	*/

int	field[] =
{
	SFIELD,
	SFIELD + 8,
	SFIELD + 14,
	SFIELD + 23,
	SFIELD + 43,
	SFIELD + 75
};

readline()
{
	int	i;		/* pointer into prlnbuf */
	int	j;		/* pointer to current field start	*/
	int	ch;		/* current character		*/
	int	cmnt;		/* comment line flag	*/
	int	spcnt;		/* consecutive space counter	*/
	int	string;		/* ASCII string flag	*/
	int	temp1;		/* temp used for line number conversion */

	temp1 = ++slnum;
	for (i = 0; i < LAST_CH_POS; i++)
		prlnbuf[i] = ' ';
	i = 3;
	while (temp1 != 0) {	/* put source line number into prlnbuf */
		prlnbuf[i--] = temp1 % 10 + '0';
		temp1 /= 10;
	}
	i = SFIELD;
	cmnt = spcnt = string = 0;
	j = 1;
	while ((ch = getc(iptr)) != '\n') {
		if(ch == '\r')
			continue;
		prlnbuf[i++] = ch;
		if ((ch == ' ') && (string == 0)) {
			if (spcnt != 0)
				--i;
			else if (cmnt == 0) {
				++spcnt;
				if (i < field[j])
					i = field[j];
				if (++j > 3) {
					spcnt = 0;
					++cmnt;
				}
			}
		}
		else if (ch == '\t') {
			prlnbuf[i - 1] = ' ';
			spcnt = 0;
			if (cmnt == 0) {
				if (i < field[j])
					i = field[j];
				if (++j > 3)
					++cmnt;
			}
			else i = (i + 8) & 0x78;
		}
		else if ((ch == ';') && (string == 0)) {
			spcnt = 0;
			if (i == SFIELD + 1)
				++cmnt;
			else if (prlnbuf[i - 2] != '\'') {
				++cmnt;
				prlnbuf[i-1] = ' ';
				if (i < field[3])
					i = field[3];
				prlnbuf[i++] = ';';
			}
		}
		else if (ch == EOF || ch == CPMEOF)
			return(-1);
		else {
			if ((ch == '"') && (cmnt == 0))
				string = string ^ 1;
			spcnt = 0;
			if (i >= LAST_CH_POS - 1)
				--i;
		}
	}
	prlnbuf[i] = 0;
	return(0);
}

/*
 * wrapup() closes the source file
 */

wrapup()
{

	fclose(iptr);
	if ((pass == DONE) && (oflag != 0)) {
		fputc('\n', optr);
		fclose(optr);
	}
	return;
}

/* symbol table print
 */

stprnt()
{
	int	i;
	int	j;
	int	k;

	fputc('\014', stdout);
	fputc('\n', stdout);
	i = 0;
	while	((j = symtab[i++]) != 0) {
		for (k = j; k > 0; k--)
			fputc(symtab[i++], stdout);
		for (k = 20 - j; k > 0; k--)
			fputc(' ', stdout);
		++i;
		j = (symtab[i++] & 0xff);
		j += (symtab[i++] << 8);
		hexcon(4, j);
		fprintf(stdout, "\t%c%c:%c%c\t%c%c%c%c\n",
			hex[3], hex[4], hex[1], hex[2],
			hex[1], hex[2], hex[3], hex[4]);
		i += 2;
	}
}
SHAR_EOF
#	End of shell archive
exit 0

brownc@utah-cs.UUCP (Eric C. Brown) (05/03/85)

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	assm2.c
#	assm3.c
# This archive created: Tue Apr  2 14:21:24 1985
# By:	James Van Ornum (AT&T-Bell Laboratories)
export PATH; PATH=/bin:$PATH
if test -f 'assm2.c'
then
	echo shar: over-writing existing file "'assm2.c'"
fi
cat << \SHAR_EOF > 'assm2.c'
#include "stdio.h"
#include "assm.d1"
#include "assm.d2"

extern	int	optab[];
extern	int	step[];

/* translate source line to machine language */

assemble()
{
	int	flg;
	int	i;		/* prlnbuf pointer */

	if ((prlnbuf[SFIELD] == ';') | (prlnbuf[SFIELD] == 0)) {
		if (pass == LAST_PASS)
			println();
		return;
	}
	lablptr = -1;
	i = SFIELD;
	udtype = UNDEF;
	if (colsym(&i) != 0 && (lablptr = stlook()) == -1)
		return;
	while (prlnbuf[++i] == ' ');	/* find first non-space */
	if ((flg = oplook(&i)) < 0) {	/* collect operation code */
		labldef(loccnt);
		if (flg == -1)
			error("Invalid operation code");
		if ((flg == -2) && (pass == LAST_PASS)) {
			if (lablptr != -1)
				loadlc(loccnt, 1, 0);
			println();
		}
		return;
	}
	if (opflg == PSEUDO)
		pseudo(&i);
	else if (labldef(loccnt) == -1)
		return;
	else {
		if (opflg == CLASS1)
			class1();
		else if (opflg == CLASS2)
			class2(&i);
		else class3(&i);
	}
}

/****************************************************************************/

/* printline prints the contents of prlnbuf */

println()
{
	if (lflag > 0)
		fprintf(stdout, "%s\n", prlnbuf);
}

/* colsym() collects a symbol from prlnbuf into symbol[],
 *    leaves prlnbuf pointer at first invalid symbol character,
 *    returns 0 if no symbol collected
 */

colsym(ip)
    int *ip;
{
	int	valid;
	int	i;
	char	ch;

	valid = 1;
	i = 0;
	while (valid == 1) {
		ch = prlnbuf[*ip];
		if (ch == '_' || ch == '.');
		else if (ch >= 'a' && ch <= 'z');
		else if (ch >= 'A' && ch <= 'Z');
		else if (i >= 1 && ch >= '0' && ch <= '9');
		else if (i == 1 && ch == '=');
		else valid = 0;
		if (valid == 1) {
			if (i < SBOLSZ - 1)
				symbol[++i] = ch;
			(*ip)++;
		}
	}
	if (i == 1) {
		switch (symbol[1]) {
		case 'A': case 'a':
		case 'X': case 'x':
		case 'Y': case 'y':
			error("Symbol is reserved (A, X or Y)");
			i = 0;
		}
	}
	symbol[0] = i;
	return(i);
}

/* symbol table lookup
 *	if found, return pointer to symbol
 *	else, install symbol as undefined, and return pointer
 */

stlook()
{
	int	found;
	int	hptr;
	int	j;
	int	nptr;
	int	pptr;
	int	ptr;

	hptr = 0;
	for (j = 0; j < symbol[0]; j++)
		hptr += symbol[j];
	hptr %= 128;
	ptr = hash_tbl[hptr];
	if (ptr == -1) {		/* no entry for this link */
		hash_tbl[hptr] = nxt_free;
		return(stinstal());
	}
	while (symtab[ptr] != 0) {	/* 0 count = end of table */
		found = 1;
		for (j = 0; j <= symbol[0]; j++) {
			if (symbol[j] != symtab[ptr + j]) {
				found = 0;
				pptr = ptr + symtab[ptr] + 4;
				nptr = (symtab[pptr + 1] << 8) + (symtab[pptr] & 0xff);
				nptr &= 0xffff;
				if (nptr == 0) {
					symtab[ptr + symtab[ptr] + 4] = nxt_free & 0xff;
					symtab[ptr + symtab[ptr] + 5] = (nxt_free >> 8) & 0xff;
					return(stinstal());
				}
				ptr = nptr;
				break;
			}
		}
		if (found == 1)
			return(ptr);
	}
	error("Symbol not found");
	return(-1);
}

/*  instal symbol into symtab
 */
stinstal()
{
register	int	j;
register	int	ptr1;
register	int	ptr2;

	ptr1 = ptr2 = nxt_free;
	if ((ptr1 + symbol[0] + 6) >= STABSZ) {
		error("Symbol table full");
		return(-1);
	}
	for (j = 0; j <= symbol[0]; j++)
		symtab[ptr1++] = symbol[j];
	symtab[ptr1] = udtype;
	nxt_free = ptr1 + 5;
	return(ptr2);
}

/* operation code table lookup
 *	if found, return pointer to symbol,
 *	else, return -1
 */

oplook(ip)
   int	*ip;
{
register	char	ch;
register	int	i;
register	int	j;
	int	k;
	int	temp[2];

	i = j = 0;
	temp[0] = temp[1] = 0;
	while((ch=prlnbuf[*ip])!= ' ' && ch!= 0 && ch!= '\t' && ch!= ';') {
		if (ch >= 'A' && ch <= 'Z')
			ch &= 0x1f;
		else if (ch >= 'a' && ch <= 'z')
			ch &= 0x1f;
		else if (ch == '.')
			ch = 31;
		else if (ch == '*')
			ch = 30;
		else if (ch == '=')
			ch = 29;
		else return(-1);
		temp[j] = (temp[j] * 0x20) + (ch & 0xff);
		if (ch == 29)
			break;
		++(*ip);
		if (++i >= 3) {
			i = 0;
			if (++j >= 2) {
				return(-1);
			}
		}
	}
	if ((j = temp[0]^temp[1]) == 0)
		return(-2);
	k = 0;
	i = step[k] - 3;
	do {
		if (j == optab[i]) {
			opflg = optab[++i];
			opval = optab[++i];
			return(i);
		}
		else if (j < optab[i])
			i -= step[++k];
		else i += step[++k];
	} while (step[k] != 0);
	return(-1);
}

/* error printing routine */

error(stptr)
   char *stptr;
{
	loadlc(loccnt, 0, 1);
	loccnt += 3;
	loadv(0,0,0);
	loadv(0,1,0);
	loadv(0,2,0);
	fprintf(stderr, "%s\n", prlnbuf);
	fprintf(stderr, "%s\n", stptr);
	errcnt++;
}

/* load 16 bit value in printable form into prlnbuf */

loadlc(val, f, outflg)
    int val;
    int f;
    int outflg;
{
	int	i;

	i = 6 + 7*f;
	hexcon(4, val);
	if (nflag == 0) {
		prlnbuf[i++]  = hex[3];
		prlnbuf[i++]  = hex[4];
		prlnbuf[i++]  = ':';
		prlnbuf[i++]  = hex[1];
		prlnbuf[i] = hex[2];
	}
	else {
		prlnbuf[i++] = hex[1];
		prlnbuf[i++] = hex[2];
		prlnbuf[i++] = hex[3];
		prlnbuf[i] = hex[4];
	}
	if ((pass == LAST_PASS)&&(oflag != 0)&&(objcnt <= 0)&&(outflg != 0)) {
		fprintf(optr, "\n;%c%c%c%c", hex[3], hex[4], hex[1], hex[2]);
		objcnt = 16;
	}
}



/* load value in hex into prlnbuf[contents[i]] */
/* and output hex characters to obuf if LAST_PASS & oflag == 1 */

loadv(val,f,outflg)
   int	val;
   int	f;		/* contents field subscript */
   int	outflg;		/* flag to output object bytes */
{

	hexcon(2, val);
	prlnbuf[13 + 3*f] = hex[1];
	prlnbuf[14 + 3*f] = hex[2];
	if ((pass == LAST_PASS) && (oflag != 0) && (outflg != 0)) {
		fputc(hex[1], optr);
		fputc(hex[2], optr);
		--objcnt;
	}
}

/* convert number supplied as argument to hexadecimal in hex[digit] (lsd)
		through hex[1] (msd)		*/

hexcon(digit, num)
    int digit;
   int	num;
{

	for (; digit > 0; digit--) {
		hex[digit] = (num & 0x0f) + '0';
		if (hex[digit] > '9')
			hex[digit] += 'A' -'9' - 1;
		num >>= 4;
	}
}

/* assign <value> to label pointed to by lablptr,
 *	checking for valid definition, etc.
 */

labldef(lval)
    int lval;
{
	int	i;

	if (lablptr != -1) {
		lablptr += symtab[lablptr] + 1;
		if (pass == FIRST_PASS) {
			if (symtab[lablptr] == UNDEF) {
				symtab[lablptr + 1] = lval & 0xff;
				i = symtab[lablptr + 2] = (lval >> 8) & 0xff;
				if (i == 0)
					symtab[lablptr] = DEFZRO;
				else	symtab[lablptr] = DEFABS;
			}
			else if (symtab[lablptr] == UNDEFAB) {
				symtab[lablptr] = DEFABS;
				symtab[lablptr + 1] = lval & 0xff;
				symtab[lablptr + 2] = (lval >> 8) & 0xff;
			}
			else {
				symtab[lablptr] = MDEF;
				symtab[lablptr + 1] = 0;
				symtab[lablptr + 2] = 0;
				error("Label multiply defined");
				return(-1);
			}
		}
		else {
			i = (symtab[lablptr + 2] << 8) +
				(symtab[lablptr+1] & 0xff);
			i &= 0xffff;
			if (i != lval && pass == LAST_PASS) {
				error("Sync error");
				return(-1);
			}
		}
	}
	return(0);
}

/* determine the value of the symbol,
 * given pointer to first character of symbol in symtab
 */

symval(ip)
    int *ip;
{
	int	ptr;
	int	svalue;

	svalue = 0;
	colsym(ip);
	if ((ptr = stlook()) == -1)
		undef = 1;		/* no room error */
	else if (symtab[ptr + symtab[ptr] + 1] == UNDEF)
		undef = 1;
	else if (symtab[ptr + symtab[ptr] + 1] == UNDEFAB)
		undef = 1;
	else svalue = ((symtab[ptr + symtab[ptr] + 3] << 8) +
		(symtab[ptr + symtab[ptr] + 2] & 0xff)) & 0xffff;
	if (symtab[ptr + symtab[ptr] + 1] == DEFABS)
		zpref = 1;
	if (undef != 0)
		zpref = 1;
	return(svalue);
}
SHAR_EOF
if test -f 'assm3.c'
then
	echo shar: over-writing existing file "'assm3.c'"
fi
cat << \SHAR_EOF > 'assm3.c'
#include "stdio.h"
#include "assm.d1"
#include "assm.d2"

/* class 1 machine operations processor - 1 byte, no operand field */

class1()
{
	if (pass == LAST_PASS) {
		loadlc(loccnt, 0, 1);
		loadv(opval, 0, 1);
		println();
	}
	loccnt++;
}


/* class 2 machine operations processor - 2 byte, relative addressing */

class2(ip)
    int *ip;
{

	if (pass == LAST_PASS) {
		loadlc(loccnt, 0, 1);
		loadv(opval, 0, 1);
		while (prlnbuf[++(*ip)] == ' ');
		if (evaluate(ip) != 0) {
			loccnt += 2;
			return;
		}
		loccnt += 2;
		if ((value -= loccnt) >= -128 && value < 128) {
			loadv(value, 1, 1);
			println();
		}
		else error("Invalid branch address");
	}
	else loccnt += 2;
}


/* class 3 machine operations processor - various addressing modes */

class3(ip)
    int *ip;
{
	char	ch;
	int	code;
	int	flag;
	int	i;
	int	ztmask;

	while ((ch = prlnbuf[++(*ip)]) == ' ');
	switch(ch) {
	case 0:
	case ';':
		error("Operand field missing");
		return;
	case 'A':
	case 'a':
		if ((ch = prlnbuf[*ip + 1]) == ' ' || ch == 0) {
			flag = ACC;
			break;
		}
	default:
		switch(ch = prlnbuf[*ip]) {
		case '#': case '=':
			flag = IMM1 | IMM2;
			++(*ip);
			break;
		case '(':
			flag = IND | INDX | INDY;
			++(*ip);
			break;
		default:
			flag = ABS | ZER | ZERX | ABSX | ABSY | ABSY2 | ZERY;
		}
		if ((flag & (INDX | INDY | ZER | ZERX | ZERY) & opflg) != 0)
			udtype = UNDEFAB;
		if (evaluate(ip) != 0)
			return;
		if (zpref != 0) {
			flag &= (ABS | ABSX | ABSY | ABSY2 | IND | IMM1 | IMM2);
			ztmask = 0;
		}
		else ztmask = ZER | ZERX | ZERY;
		code = 0;
		i = 0;
		while (( ch = prlnbuf[(*ip)++]) != ' ' && ch != 0 && i++ < 4) {
			code *= 8;
			switch(ch) {
			case ')':		/* ) = 4 */
				++code;
			case ',':		/* , = 3 */
				++code;
			case 'X':		/* X = 2 */
			case 'x':
				++code;
			case 'Y':		/* Y = 1 */
			case 'y':
				++code;
				break;
			default:
				flag = 0;
			}
		}
		switch(code) {
		case 0:		/* no termination characters */
			flag &= (ABS | ZER | IMM1 | IMM2);
			break;
		case 4:		/* termination = ) */
			flag &= IND;
			break;
		case 25:		/* termination = ,Y */
			flag &= (ABSY | ABSY2 | ZERY);
			break;
		case 26:		/* termination = ,X */
			flag &= (ABSX | ZERX);
			break;
		case 212:		/* termination = ,X) */
			flag &= INDX;
			break;
		case 281:		/* termination = ),Y */
			flag &= INDY;
			break;
		default:
			flag = 0;
		}
	}
	if ((opflg &= flag) == 0) {
		error("Invalid addressing mode");
		return;
	}
	if ((opflg & ztmask) != 0)
		opflg &= ztmask;
	switch(opflg) {
	case ACC:		/* single byte - class 3 */
		if (pass == LAST_PASS) {
			loadlc(loccnt, 0, 1);
			loadv(opval + 8, 0, 1);
			println();
		}
		loccnt++;
		return;
	case ZERX: case ZERY:	/* double byte - class 3 */
		opval += 4;
	case INDY:
		opval += 8;
	case IMM2:
		opval += 4;
	case ZER:
		opval += 4;
	case INDX: case IMM1:
		if (pass == LAST_PASS) {
			loadlc(loccnt, 0, 1);
			loadv(opval, 0, 1);
			loadv(value, 1, 1);
			println();
		}
		loccnt += 2;
		return;
	case IND:		/* triple byte - class 3 */
		opval += 16;
	case ABSX:
	case ABSY2:
		opval += 4;
	case ABSY:
		opval += 12;
	case ABS:
		if (pass == LAST_PASS) {
			opval += 12;
			loadlc(loccnt, 0, 1);
			loadv(opval, 0, 1);
			loadv(value, 1, 1);
			loadv(value >> 8, 2, 1);
			println();
		}
		loccnt += 3;
		return;
	default:
		error("Invalid addressing mode");
		return;
	}
}

/* pseudo operations processor */

pseudo(ip)
    int *ip;
{
	int	count;
	int	i;
	int	tvalue;

	switch(opval) {
	case 0:				/* .byte pseudo */
		labldef(loccnt);
		loadlc(loccnt, 0, 1);
		while (prlnbuf[++(*ip)] == ' ');	/*    field	*/
		count = 0;
		do {
			if (prlnbuf[*ip] == '"') {
				while ((tvalue = prlnbuf[++(*ip)]) != '"') {
					if (tvalue == 0) {
						error("Unterminated ASCII string");
						return;
					}
					if (tvalue == '\\')
						switch(tvalue = prlnbuf[++(*ip)]) {
						case 'n':
							tvalue = '\n';
							break;
						case 't':
							tvalue = '\t';
							break;
						}
					loccnt++;
					if (pass == LAST_PASS) {
						loadv(tvalue, count, 1);
						if (++count >= 3) {
							println();
							for (i = 0; i < SFIELD; i++)
								prlnbuf[i] = ' ';
							prlnbuf[i] = 0;
							count = 0;
							loadlc(loccnt, 0, 1);
						}
					}
				}
				++(*ip);
			}
			else {
				if (evaluate(ip) != 0) {
					loccnt++;
					return;
				}
				loccnt++;
				if (value > 0xff) {
					error("Operand field size error");
					return;
				}
				else if (pass == LAST_PASS) {
					loadv(value, count, 1);
					if (++count >= 3) {
						println();
						for (i = 0; i < SFIELD; i++)
							prlnbuf[i] = ' ';
						prlnbuf[i] = 0;
						count = 0;
						loadlc(loccnt, 0, 1);
					}
				}
			}
		} while (prlnbuf[(*ip)++] == ',');
		if ((pass == LAST_PASS) && (count != 0))
			println();
		return;
	case 1:				/* = pseudo */
		while (prlnbuf[++(*ip)] == ' ');
		if (evaluate(ip) != 0)
			return;
		labldef(value);
		if (pass == LAST_PASS) {
			loadlc(value, 1, 0);
			println();
		}
		return;
	case 2:				/* .word pseudo */
		labldef(loccnt);
		loadlc(loccnt, 0, 1);
		while (prlnbuf[++(*ip)] == ' ');
		do {
			if (evaluate(ip) != 0) {
				loccnt += 2;
				return;
			}
			loccnt += 2;
			if (pass == LAST_PASS) {
				loadv(value, 0, 1);
				loadv(value>>8, 1, 1);
				println();
				for (i = 0; i < SFIELD; i++)
					prlnbuf[i] = ' ';
				prlnbuf[i] = 0;
				loadlc(loccnt, 0, 1);
			}
		} while (prlnbuf[(*ip)++] == ',');
		return;
	case 3:				/* *= pseudo */
		while (prlnbuf[++(*ip)] == ' ');
		if (prlnbuf[*ip] == '*') {
			if (evaluate(ip) != 0)
				return;
			if (undef != 0) {
				error("Undefined symbol in operand field.");
				return;
			}
			tvalue = loccnt;
		}
		else {
			if (evaluate(ip) != 0)
				return;
			if (undef != 0) {
				error("Undefined symbol in operand field.");
				return;
			}
			tvalue = value;
		}
		loccnt = value;
		labldef(tvalue);
		if (pass == LAST_PASS) {
			objcnt = 0;
			loadlc(tvalue, 1, 0);
			println();
		}
		return;
	case 4:				/* .list pseudo */
		if (lflag >= 0)
			lflag = 1;
		return;
	case 5:				/* .nlst pseudo */
		if (lflag >= 0)
			lflag = iflag;
		return;
	case 6:				/* .dbyt pseudo */
		labldef(loccnt);
		loadlc(loccnt, 0, 1);
		while (prlnbuf[++(*ip)] == ' ');
		do {
			if (evaluate(ip) != 0) {
				loccnt += 2;
				return;
			}
			loccnt += 2;
			if (pass == LAST_PASS) {
				loadv(value>>8, 0, 1);
				loadv(value, 1, 1);
				println();
				for (i = 0; i < SFIELD; i++)
					prlnbuf[i] = ' ';
				prlnbuf[i] = 0;
				loadlc(loccnt, 0, 1);
			}
		} while (prlnbuf[(*ip)++] == ',');
		return;
	}
}

/* evaluate expression */

evaluate(ip)
   int	*ip;
{
	int	tvalue;
	int	invalid;
	int	parflg, value2;
	char	ch;
	char	op;
	char	op2;

	op = '+';
	parflg = zpref = undef = value = invalid = 0;
/* hcj: zpref should reflect the value of the expression, not the value of
   the intermediate symbols
*/
	while ((ch=prlnbuf[*ip]) != ' ' && ch != ')' && ch != ',' && ch != ';') {
		tvalue = 0;
		if (ch == '$' || ch == '@' || ch == '%')
			tvalue = colnum(ip);
		else if (ch >= '0' && ch <= '9')
			tvalue = colnum(ip);
		else if (ch >= 'a' && ch <= 'z')
			tvalue = symval(ip);
		else if (ch >= 'A' && ch <= 'Z')
			tvalue = symval(ip);
		else if ((ch == '_') || (ch == '.'))
			tvalue = symval(ip);
		else if (ch == '*') {
			tvalue = loccnt;
			++(*ip);
		}
		else if (ch == '\'') {
			++(*ip);
			tvalue = prlnbuf[*ip] & 0xff;
			++(*ip);
		}
		else if (ch == '[') {
			if (parflg == 1) {
				error("Too many ['s in expression");
				invalid++;
			}
			else {
				value2 = value;
				op2 = op;
				value = tvalue = 0;
				op = '+';
				parflg = 1;
			}
			goto next;
		}
		else if (ch == ']') {
			if (parflg == 0) {
				error("No matching [ for ] in expression");
				invalid++;
			}
			else {
				parflg = 0;
				tvalue = value;
				value = value2;
				op = op2;
			}
			++(*ip);
		}
		switch(op) {
		case '+':
			value += tvalue;
			break;
		case '-':
			value -= tvalue;
			break;
		case '/':
			value = (unsigned) value/tvalue;
			break;
		case '*':
			value *= tvalue;
			break;
		case '%':
			value = (unsigned) value%tvalue;
			break;
		case '^':
			value ^= tvalue;
			break;
		case '~':
			value = ~tvalue;
			break;
		case '&':
			value &= tvalue;
			break;
		case '|':
			value |= tvalue;
			break;
		case '>':
			tvalue >>= 8;		/* fall through to '<' */
		case '<':
			if (value != 0) {
				error("High or low byte operator not first in operand field");
			}
			value = tvalue & 0xff;
			zpref = 0;
			break;
		default:
			invalid++;
		}
		if ((op=prlnbuf[*ip]) == ' '
				|| op == ')'
				|| op == ','
				|| op == ';')
			break;
		else if (op != ']')
next:			++(*ip);
	}
	if (parflg == 1) {
		error("Missing ] in expression");
		return(1);
	}
	if (value < 0 || value >= 256) {
		zpref = 1;
	}
	if (undef != 0) {
		if (pass != FIRST_PASS) {
			error("Undefined symbol in operand field");
			invalid++;
		}
		value = 0;
	}
	else if (invalid != 0)
	{
		error("Invalid operand field");
	}
	else {
/*
 This is the only way out that may not signal error
*/
		if (value < 0 || value >= 256) {
			zpref = 1;
		}
		else {
			zpref = 0;
		}
	}
	return(invalid);
}

/* collect number operand		*/

colnum(ip)
	int	*ip;
{
	int	mul;
	int	nval;
	char	ch;

	nval = 0;
	if ((ch = prlnbuf[*ip]) == '$')
		mul = 16;
	else if (ch >= '1' && ch <= '9') {
		mul = 10;
		nval = ch - '0';
	}
	else if (ch == '@' || ch == '0')
		mul = 8;
	else if (ch == '%')
		mul = 2;
	while ((ch = prlnbuf[++(*ip)] - '0') >= 0) {
		if (ch > 9) {
			ch -= ('A' - '9' - 1);
			if (ch > 15)
				ch -= ('a' - 'A');
			if (ch > 15)
				break;
			if (ch < 10)
				break;
		}
		if (ch >= mul)
			break;
		nval = (nval * mul) + ch;
	}
	return(nval);
}
SHAR_EOF
#	End of shell archive
exit 0