	TITLE	'ASM SCANNER MODULE'
	org	0
base	equ	$

	ORG	1100H
	JMP	ENDMOD	;END OF THIS MODULE
	JMP	INITS	;INITIALIZE THE SCANNER
	JMP	SCAN	;CALL THE SCANNER
;
;
;	ENTRY POINTS IN I/O MODULE
IOMOD	EQU	base+200H
GNCF	EQU	IOMOD+6H
WOBUFF	EQU	IOMOD+15H
PERR	EQU	IOMOD+18H
;
LASTC:	DS	1	;LAST CHAR SCANNED
NEXTC:	DS	1	;LOOK AHEAD CHAR
STYPE:	DS	1	;RADIX INDICATOR
;
;	COMMON EQUATES
PBMAX	EQU	90	;MAX PRINT SIZE
PBUFF	EQU	base+10CH	;PRINT BUFFER
PBP	EQU	PBUFF+PBMAX	;PRINT BUFFER POINTER
;
TOKEN	EQU	PBP+1	;CURRENT TOKEN UDER SCAN
VALUE	EQU	TOKEN+1	;VALUE OF NUMBER IN BINARY
ACCLEN	EQU	VALUE+2	;ACCUMULATOR LENGTH
ACMAX	EQU	64	;MAX ACCUMULATOR LENGTH
ACCUM	EQU	ACCLEN+1
;
EVALUE	EQU	ACCUM+ACMAX	;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP	EQU	EVALUE+2	;CURRENT SYMBOL TOP
SYMAX	EQU	SYTOP+2		;MAX ADDRESS+1
;
PASS	EQU	SYMAX+2	;CURRENT PASS NUMBER
FPC	EQU	PASS+1	;FILL ADDRESS FOR NEXT HEX BYTE
ASPC	EQU	FPC+2	;ASSEMBLER'S PSEUDO PC
;
;	GLOBAL EQUATES
IDEN	EQU	1	;IDENTIFIER
NUMB	EQU	2	;NUMBER
STRNG	EQU	3	;STRING
SPECL	EQU	4	;SPECIAL CHARACTER
;
PLABT	EQU	0001B	;PROGRAM LABEL
DLABT	EQU	0010B	;DATA LABEL
EQUT	EQU	0100B	;EQUATE
SETT	EQU	0101B	;SET
MACT	EQU	0110B	;MACRO
;
EXTT	EQU	1000B	;EXTERNAL
REFT	EQU	1011B	;REFER
GLBT	EQU	1100B	;GLOBAL
;
BINV	EQU	2
OCTV	EQU	8
DECV	EQU	10
HEXV	EQU	16
CR	EQU	0DH
LF	EQU	0AH
EOF	EQU	1AH
TAB	EQU	09H	;TAB CHARACTER
;
;
;	UTILITY SUBROUTINES
GNC:	;GET NEXT CHARACTER AND ECHO TO PRINT FILE
	CALL	GNCF
	PUSH	PSW
	CPI	CR
	JZ	GNC0
	CPI	LF	;IF LF THEN DUMP CURRENT BUFFER
	JZ	GNC0
;
	;NOT A CR OR LF, PLACE INTO BUFFER IF THERE IS ENOUGH ROOM
	LDA	PBP
	CPI	PBMAX
	JNC	GNC0
;	ENOUGH ROOM, PLACE INTO BUFFER
	MOV	E,A
	MVI	D,0	;DOUBLE PRECISION PBP IN D,E
	INR	A
	STA	PBP	;INCREMENTED PBP IN MEMORY
	LXI	H,PBUFF
	DAD	D	;PBUFF(PBP)
	POP	PSW
	MOV	M,A	;PBUFF(PBP) = CHAR
	RET
GNC0:	;CHAR NOT PLACED INTO BUFFER
	POP	PSW
	RET
;
INITS:	;INITIALIZE THE SCANNER
	CALL	ZERO
	STA	NEXTC	;CLEAR NEXT CHARACTER
	STA	PBP
	MVI	A,LF	;SET LAST CHAR TO LF
	STA	LASTC
	CALL	WOBUFF	;CLEAR BUFFER
	MVI	A,16	;START OF PRINT LINE
	STA	PBP
	RET
;
ZERO:	XRA	A
	STA	ACCLEN
	STA	STYPE
	RET
;
SAVER:	;STORE THE NEXT CHARACTER INTO THE ACCUMULATOR AND UPDATE ACCLEN
	LXI	H,ACCLEN
	MOV	A,M
	CPI	ACMAX
	JC	SAV1	;JUMP IF NOT UP TO LAST POSITION
	MVI	M,0
	CALL	ERRO
SAV1:	MOV	E,M	;D,E WILL HOLD INDEX
	MVI	D,0
	INR	M	;ACCLEN INCREMENTED
	INX	H	;ADDRESS ACCUMULATOR
	DAD	D	;ADD INDEX TO ACCUMULATOR
	LDA	NEXTC	;GET CHARACTER
	MOV	M,A	;INTO ACCUMULATOR
	RET
;
TDOLL:	;TEST FOR DOLLAR SIGN, ASSUMING H,L ADDRESS NEXTC
	MOV	A,M
	CPI	'$'
	RNZ
	XRA	A	;TO GET A ZERO
	MOV	M,A	;CLEARS NEXTC
	RET		;WITH ZERO FLAG SET
;
NUMERIC:	;CHECK NEXTC FOR NUMERIC, RETURN ZERO FLAG IF NOT NUMERIC
	LDA	NEXTC
	SUI	'0'
	CPI	10
;	CARRY RESET IF NUMERIC
	RAL
	ANI	1B	;ZERO IF NOT NUMERIC
	RET
;
HEX:	;RETURN ZERO FLAG IF NEXTC IS NOT HEXADECIMAL
	CALL	NUMERIC
	RNZ		;RETURNS IF 0-9
	LDA	NEXTC
	SUI	'A'
	CPI	6
;	CARRY SET IF OUT OF RANGE
	RAL
	ANI	1B
	RET
;
LETTER:	;RETURN ZERO FLAG IF NEXTC IS NOT A LETTER
	LDA	NEXTC
	SUI	'A'
	CPI	26
	RAL
	ANI	1B
	RET
;
ALNUM:	;RETURN ZERO FLAG IF NOT ALPHANUMERIC
	CALL	LETTER
	RNZ
	CALL	NUMERIC
	RET
;
TRANS:	;TRANSLATE TO UPPER CASE
	LDA	NEXTC
	CPI	'A' OR 1100000B	;LOWER CASE A
	RC				;CARRY IF LESS THAN LOWER A
	CPI	('Z' OR 1100000B)+1	;LOWER CASE Z
	RNC				;NO CARRY IF GREATER THAN LOWER Z
	ANI	1011111B		;CONVERT TO UPPER CASE
	STA	NEXTC
	RET
;
GNCN:	;GET CHARACTER AND STORE TO NEXTC
	CALL	GNC
	STA	NEXTC
	push	psw	;*** Patch ***
	lda	token	;Fixes upper case conversion
	cpi	strng	;of characters in a string
	cnz	TRANS	;TRANSLATE TO UPPER CASE
	pop	psw
	RET
;
EOLT:	;END OF LINE TEST FOR COMMENT SCAN
	CPI	CR
	RZ
	CPI	EOF
	RZ
	CPI	'!'
	RET
;
SCAN:	;FIND NEXT TOKEN IN INPUT STREAM
	XRA	A
	STA	TOKEN
	CALL	ZERO
;
;	DEBLANK
DEBL:	LDA	NEXTC
	CPI	TAB	;TAB CHARACTER TREATED AS BLANK OUTSIDE STRING
	JZ	DEB0
	CPI	';'	;MAY BE A COMMENT
	JZ	DEB1	;DEBLANK THROUGH COMMENT
	CPI	'*'	;PROCESSOR TECH COMMENT
	JNZ	DEB2	;NOT *
	LDA	LASTC
	CPI	LF	;LAST LINE FEED?
	JNZ	DEB2	;NOT LF*
;	COMMENT FOUND, REMOVE IT
DEB1:	CALL	GNCN
	CALL	EOLT	;CR, EOF, OR !
	JZ	FINDL	;HANDLE END OF LINE
	JMP	DEB1	;OTHERWISE CONTINUE SCAN
DEB2:	ORI	' '	;MAY BE ZERO
	CPI	' '
	JNZ	FINDL
DEB0:	CALL	GNCN	;GET NEXT AND STORE TO NEXTC
	JMP	DEBL
;
;	LINE DEBLANKED, FIND TOKEN TYPE
FINDL:	;LOOK FOR LETTER, DECIMAL DIGIT, OR STRING QUOTE
	CALL	LETTER
	JZ	FIND0
	MVI	A,IDEN
	JMP	STOKEN
;
FIND0:	CALL	NUMERIC
	JZ	FIND1
	MVI	A,NUMB
	JMP	STOKEN
;
FIND1:	LDA	NEXTC
	CPI	''''
	JNZ	FIND2
	XRA	A
	STA	NEXTC	;DON'T STORE THE QUOTE
	MVI	A,STRNG
	JMP	STOKEN
;
FIND2:	;ASSUME IT IS A SPECIAL CHARACTER
	CPI	LF	;IF LF THEN DUMP THE BUFFER
	JNZ	FIND3
;	LF FOUND
	LDA	PASS
	ORA	A
	CNZ	WOBUFF
	LXI	H,PBUFF	;CLEAR ERROR CHAR ON BOTH PASSES
	MVI	M,' '
	MVI	A,16
	STA	PBP	;START NEW LINE
FIND3:	MVI	A,SPECL
;
STOKEN:	STA	TOKEN
;
;
;	LOOP WHILE CURRENT ITEM IS ACCUMULATING
SCTOK:	LDA	NEXTC
	STA	LASTC	;SAVE LAST CHARACTER
	ORA	A
	CNZ	SAVER	;STORE CHARACTER INTO ACCUM IF NOT ZERO
	CALL	GNCN	;GET NEXT TO NEXTC
	LDA	TOKEN
	CPI	SPECL
	RZ		;RETURN IF SPECIAL CHARACTER
	CPI	STRNG
	CNZ	TRANS	;TRANSLATE TO UPPER CASE IF NOT IN STRING
	LXI	H,NEXTC
	LDA	TOKEN
;
	CPI	IDEN
	JNZ	SCT2
;
;	ACCUMULATING AN IDENTIFIER
	CALL	TDOLL	;$?
	JZ	SCTOK	;IF SO, SKIP IT
	CALL	ALNUM	;ALPHA NUMERIC?
	RZ		;RETURN IF END
;	NOT END OF THE IDENTIFIER
	JMP	SCTOK
;
SCT2:	;NOT SPECIAL OR IDENT, CHECK NUMBER
	CPI	NUMB
	JNZ	SCT3
;
;	ACCUMULATING A NUMBER, CHECK FOR $
	CALL	TDOLL
	JZ	SCTOK	;SKIP IF FOUND
	CALL	HEX	;HEX CHARACTER?
	JNZ	SCTOK	;STORE IT IF FOUND
;	END OF NUMBER, LOOK FOR RADIX INDICATOR
;
	LDA	NEXTC
	CPI	'O'	;OCTAL INDICATOR
	JZ	NOCT
	CPI	'Q'	;OCTAL INDICATOR
	JNZ	NUM2
;
NOCT:	;OCTAL
	MVI	A,OCTV
	JMP	SSTYP
;
NUM2:	CPI	'H'
	JNZ	NUM3
	MVI	A,HEXV
SSTYP:	STA	STYPE
	XRA	A
	STA	NEXTC	;CLEARS THE LOOKAHEAD CHARACTER
	JMP	NCON
;
;	RADIX MUST COME FROM ACCUM
NUM3:	LDA	LASTC
	CPI	'B'
	JNZ	NUM4
	MVI	A,BINV
	JMP	SSTY1
;
NUM4:	CPI	'D'
	MVI	A,DECV
	JNZ	SSTY2
SSTY1:	LXI	H,ACCLEN
	DCR	M	;ACCLEN DECREMENTED TO REMOVE RADIX INDICATOR
SSTY2:	STA	STYPE
;
NCON:	;NUMERIC CONVERSION OCCURS HERE
	LXI	H,0
	SHLD	VALUE	;VALUE ACCUMULATES BINARY EQUIVALENT
	LXI	H,ACCLEN
	MOV	C,M	;C=ACCLEN
	INX	H	;ADDRESSES ACCUM
CLOP:	;NEXT DIGIT IS PROCESSED HERE
	MOV	A,M
	INX	H	;READY FOR NEXT LOOP
	CPI	'A'
	JNC	CLOP1	;NOT HEX A-F
	SUI	'0'	;NORMALIZE
	JMP	CLOP2
;
CLOP1:	;HEX A-F
	SUI	'A'-10
CLOP2:	;CHECK SIZE AGAINST RADIX
	PUSH	H	;SAVE ACCUM ADDR
	PUSH	B	;SAVE CURRENT POSITION
	MOV	C,A
	LXI	H,STYPE
	CMP	M
	CNC	ERRV	;VALUE ERROR IF DIGIT>=RADIX
	MVI	B,0	;DOUBLE PRECISION DIGIT
	MOV	A,M	;RADIX TO ACCUMULATOR
	LHLD	VALUE
	XCHG		;VALUE TO D,E - ACCUMULATE RESULT IN H,L
	LXI	H,0	;ZERO ACCUMULATOR
CLOP3:	;LOOP UNTIL RADIX GOES TO ZERO
	ORA	A
	JZ	CLOP4
	RAR		;TEST LSB
	JNC	TTWO	;SKIP SUMMING OPERATION IF LSB=0
	DAD	D	;ADD IN VALUE
TTWO:	;MULTIPLY VALUE * 2 FOR SHL OPERATION
	XCHG
	DAD	H
	XCHG
	JMP	CLOP3
;
;
CLOP4:	;END OF NUMBER CONVERSION
	DAD	B	;DIGIT ADDED IN
	SHLD	VALUE
	POP	B
	POP	H
	DCR	C	;MORE DIGITS?
	JNZ	CLOP
	RET		;DONE WITH THE NUMBER
;
SCT3:	;MUST BE A STRING
	LDA	NEXTC
	CPI	CR	;END OF LINE?
	JZ	ERRO	;AND RETURN
	CPI	''''
	JNZ	SCTOK
	CALL	GNCN
	CPI	''''
	RNZ		;RETURN IF SINGLE QUOTE ENCOUNTERED
	JMP	SCTOK	;OTHERWISE TREAT AS ONE QUOTE
;
;	END OF SCANNER
;
;	ERROR MESSAGE ROUTINES
ERRV:	;'V' VALUE ERROR
	PUSH	PSW
	MVI	A,'V'
	JMP	ERR
;
ERRO:	;'O' OVERFLOW ERROR
	PUSH	PSW
	MVI	A,'O'
	JMP	ERR
;
ERR:	;PRINT ERROR MESSAGE
	PUSH	B
	PUSH	H
	CALL	PERR
	POP	H
	POP	B
	POP	PSW
	RET
;
ENDMOD	EQU	($ AND 0FFE0H) + 20H
	END
