[comp.sources.amiga] v02i028: Web, an assembly language pre-processor.

lee@s.cc.purdue.edu.UUCP (09/23/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	atow.w
#	web.w
# This archive created: Mon Sep 21 23:29:18 1987
# By:	Craig Norborg (Purdue University Computing Center)
cat << \SHAR_EOF > atow.w

	idnt  Mtoequals

	section  one

1. This little utility makes a copy of a file with
	all control characters changed to 'X's.
	To assemble: web mtoequals.w
			     assem mtoequals.a -o mtoequals.o
			     alink mtoequals.o to mtoequals
			     delete mtoequals.a
			     delete mtoequals.o
						 --- Greg Lee, July 1, 1986

	--Macro definitions for assembler
	--EQU statements for assembler
	--Definitions of library references

2. Here is where execution starts.

Main

	   define   push  -(SP).L
	   define   pop    (SP)+
	   define   chr    D0.B

	--Get file name from input line
	--Open input and output files

 {
	--Read a line
	tst.l	 l_length
	beq 	 windup

	a1	=	^obuf
	a2.l	=	input_line

	chr	=	(input_line)+
	chr	?	9
	= +	chr  =  ' '  ;

	chr	?	' '
	= {	{  (input_line)+.b  ?  ' '
		   beq	}

		input_line	-=	1
		--Check for equals instruction
		bne	6
		d2.b	=	chr

		d4.b	=	(input_line)
		d4.b	?	'q'
		= +	input_line	+=	1	;

		d1	=	0
		(input_line).b  ?  '.'
		= {	input_line	+=	1
			d1.b	=	(input_line)+
		}

		chr	=	(input_line)+
		chr	?	9
		!= [	chr	?	' '
			bne	6
		]
		{  (input_line)+.b  ?  ' '
		   beq	}

		a3.l	=	^-1(input_line)

		[  chr	=	(input_line)+
		   chr	?  10;	beq  6
		   chr  ?  ''''
		   = +	input_line  +=  2  ;
		   chr  ?  ','
		   bne	]
		
		(a1)+.b		=	9
		l_length	=	5

		(input_line).b	?	'D'
		= +	(input_line).b	=	'd'	;
		(input_line).b	?	'A'
		= +	(input_line).b	=	'a'	;
		(input_line).b	?	'S'
		= {	1(input_line).b	?	'P'
			= {	(input_line).b	=	'a'
				1(input_line).b	=	'7'
			}
		}

		{  chr	=  (input_line)+
		   chr  ?  9;	beq	6
		   chr  ?  10;	beq	6
		   chr  ?  ' '
		   = [	-2(input_line).b  ?  ''''
			bne	6
		   ]
		   (a1)+.b	=	chr
		   l_length	+=	1
		   ->	}

		d4.b	?	'q'
		= {	d1.b	?	'l'
			= +	clr.b	d1	;
		}

		tst.b	d1
		!= {	(a1)+.b	=	'.'
			(a1)+.b	=	d1
			l_length  += 	2
		}

		(a1)+.b		=	9
		d2.b	?	'a'
		= {	(a1)+.b	=	'+'
			l_length  +=  1
		}
		d2.b	?	's'
		= {	(a1)+.b	=	'-'
			l_length  +=  1
		}

		(a1)+.b		=	'='
		d2.b	?	'c'
		= +	-1(a1).b   =	'?'	;
		(a1)+.b		=	9
		d2.b	?	'l'
		= {	(a1)+.b  =  '^'
			l_length  +=  1
		}

		d4.b	?	'q'
		= +	clr.b	d1	;

		{  chr		=	(a3)+
		   chr  ?  ',';	beq	6
		   (a1)+.b	=	chr
		   l_length	+=	1
		   chr	?  '#'
		   = {	tst.b	d1
			!= [	(a3).b	?  ''''
				bne	6
			]
			a1	-=	1
			l_length  -=	1
		   }
		   ->	}

		(a1)+.b		=	10
		a2		=	^ obuf

	}


	arg`a	 =  ohandle
	arg`b	 =  a2
	call	Write
	l_length  ?  d0
  beq	 }

	print	 prob

windup 	    7 finished output
	chr    =  infname
	!=	 {
	  arg`a  =  ohandle; call     Close
	  arg`a  =  ihandle; call     Close
	  ->   {
	   abort1:  arg`a  =  ihandle;	call	 Close
	   abort:   print    nogo
	   }
	}
	d0 =  0


--Check for equals instruction
	chr	=	(input_line)+
	chr	?	'm'
	!= {	chr	?	'l'
		!= {	chr	?	'c'
			!= {	chr	?	'a'
				!= {	chr	?	's'
					bne	'
					(input_line)+.b  ?  'u'
					bne	'
					(input_line)+.b  ?  'b'
					->	'
				}
				(input_line)+.b  ?  'd'
				bne	'
				(input_line)+.b  ?  'd'
				->	'
			}
			(input_line)+.b  ?  'm'
			bne	'
			(input_line)+.b  ?  'p'
			->	'
		}
		(input_line)+.b  ?  'e'
		bne	'
		(input_line)+.b  ?  'a'
		->	'
	}
	(input_line)+.b  ?  'o'
	bne	'
	(input_line)+.b  ?  'v'
	bne	'
	(input_line)+.b  ?  'e'
	= {	(input_line).b  ?  ' ';	beq	'
		(input_line).b  ?  9;	beq	'
		(input_line).b  ?  '.'; beq	'
		(input_line)+.b  ?  'q'
	}


6 We make two copies of the name given in the command tail.
  The last character of the second copy is changed to 'a', and
  this second copy is used as the name of the output file.

--Get file name from input line

	define	 command_tail	A0.L
	define	 tail_length	D0
	define	 input_name	A1.L
	define	 output_name	A2.L
	define	 fn_char	D1.B

	input_name     =  ^infname
	output_name  =	input_name
	->		 next_fname_char
	{  fn_char  =  (command_tail)+
	   fn_char  ?  ' ' + 1;   blt	6
	   (input_name)+.b  =  fn_char
	   tail_length -= 1
next_fname_char
	   tst.l    tail_length
	   bne	 }
	clr.b	 (input_name)

	exg 	 input_name,output_name
	output_name	 =  ^outfname
	{	(output_name)+.b  =  (input_name)+;   =  }
	output_name	-=  1

	-1(output_name).b	?	'a'
	= {	-2(output_name).b	?	'.'
		= {	-1(output_name).b  =  'w'
			->	'
		}
	}

	(output_name)+.b = '.';  (output_name)+.b = 'n'
	clr.b	 (output_name)

6 AmigaDOS stuff.

--Open input and output files

	   define   arg`a  D1.L    7 first argument to AmigaDOS function
	   define   arg`b  D2.L    7 second argument

	   long  ohandle
	   long  chandle
	   long  ihandle

	--Initialize standard input and output

	a1	   = ^infname
	tst.b	 (A1)
	beq 	 abort

	arg`a  =  a1
	arg`b  =  #1005
	call	 Open; tst.l  D0; beq  abort
	ihandle  =  d0

	arg`a  =  #outfname
	arg`b  =  #1006
	call	 Open; tst.l  D0; beq  abort1
	ohandle  =  d0

	6 Buffer is refilled whenever we can't find a complete line
(ending in newline). The count in D3 includes the final newline.
Thus returning a count of zero can be used as the signal that
the file is exhausted.

--Read a line

	define	 input_line	 A0.L
	define	 l_length	 D3.L
	define	 new_line	#10
	define	 chars_remaining D2.B
	define	 partial_line	 A1.L
	byte	 bufchcount

7 return input_line pointing to line and l_length length of line
	input_line  =  bufptr
	push	    =  input_line
	l_length    =  0      7 no chars in line yet
7 back to here when was necessary to read more from file
.rdln.cont
	moveq  #0,chars_remaining
	chars_remaining   = bufchcount
	bmi 	 rdln.keep.info  7 this means file is exhausted
	beq 	 .rdln.more

	chars_remaining.l  -= 1
	{ chr	=	(input_line)+
	  chr	?  new_line
	  beq	   rdln.keep.one
7	  chr	?	9
7	  = +  -1(input_line).b  =  ' '  ;
	  l_length.b += 1
	  l_length.b  ?  #ibufLen
	  beq	   rdln.keep.info
	  dbra	   chars_remaining,}
7 ran out of chars -- go get more
	->	 .rdln.more
7 have one line -- check not empty
rdln.keep.one
	l_length.b  += 1
rdln.keep.info
	bufptr.l     =	input_line
	bufchcount   =	chars_remaining
	input_line   =	pop
	->	   '

.rdln.more
7 have partial line in buffer with l_length chars in it
	partial_line = pop   7 beginning of partial line
7 while l_length > 0 move chars back to beginning of buffer
	input_line  =  ^ibuf
	push	    =  input_line    7 for ret.
	push	    =  l_length
	l_length.b -= 1
	+{ {  (input_line)+.b =  (partial_line)+
		  dbra     l_length,}
	 }
7 fill remainder of buffer with 80-(l_length) chars
	l_length    =  80
	d0.l	    =  pop
	l_length.b -=  d0
	push	    =  d0

	partial_line  = ^ibuf
	partial_line += d0
	push	      =   partial_line	 7 save where to continue processing line
	arg`a  =   ihandle
	arg`b  =   partial_line
	call	 Read

	tst.b	 D0
	= +  st   D0 ;
	bufchcount	= d0
	input_line	= pop	  7 continue processing here
	l_length	= pop	  7 chars scanned so far
	->	  .rdln.cont


Display string
7	message to console
msg
	arg`a	   =  chandle
	l_length   = 0
	l_length.b = (a0)+
	arg`b	   =  a0
	call	 Write

	   6 AmigaDos stuff.

--Initialize standard input and output
ioinit
	move.l	 sysBase,A6	   7 ready call to OpenLibrary
	lea 	 libname,A1
	moveq	 #0,D0
	call	 OpenLibrary
	move.l	 D0,A6
7 obtain file handles for output and input opened by CLI
	call	 Output
	ohandle  =  d0
	chandle  =  d0
	call	 Input
	ihandle  =  d0



	   6

Data sections

	section  three,bss

olen		 ds.b  1
obuf		 ds.b  80
ilen		 ds.b  1
ibuf		 ds.b  ibufLen
7 now on word boundary

infname	 ds.b  30
outfname	 ds.b  30



	section two,data



libname  dc.b  'dos.library',0
bufptr 	    dc.l  ibuf
	cnop	 0,2

		  bstr  nogo,<couldn''t open file>
		  bstr  prob,<problem with output file>

	section  one


	   6

--EQU statements for assembler
sysBase	 equ   4
ibufLen	 equ   80

	   6

--Macro definitions for assembler

lref  macro
_LVO\1 	 equ  -6*(\2+4)
	   endm

call  macro
	   jsr	 _LVO\1(A6)
	   endm

print macro
	   lea	 \1,A0
	   bsr	 msg
	   endm

bstr  macro
\1    dc.b  1$-*-1
	   dc.b  '\2',10
1$
	   endm

6 Following to avoid slow linking with amiga.lib

--Definitions of library references

	lref	 OpenLibrary,88

	lref	 Output,6
	lref	 Input,5
	lref	 Write,4
	lref	 Read,3
	lref	 DeleteFile,8
	lref	 Open,1
	lref	 Close,2
	lref	 IoErr,18
	lref	 LoadSeg,21
	lref	 UnLoadSeg,22
	lref	 IsInteractive,32


SHAR_EOF
cat << \SHAR_EOF > web.w

1.  Web preprocesses structured assembler programs and produces
an output file for the assembler.  This very file must itself be
preprocessed by web before assembly, so it will serve as an example
of web usage.  There is a file 'web.doc' with more information.

	6 The structure so far allows for:
	(1)  argumentless macros (whose names begin with 2 hyphens),
	(2)  a variant syntax for calling procedures (names begin with capital),
	(3)  defined symbols,
	(4)  statement grouping with '{...}' and '+...;',
	(5)  alternate symbols for branch instructions,
	(6)  infix statments with '=' and '?',
	(7)  simple data declarations,
and	(8)  new ways of giving comments.

	6 To assemble this program:
	      web web.w
	      assem web.a -o web.o
	      delete web.a
	      alink web.o to web
	      delete web.o
						--- Greg Lee, July 4, 1986

2. Assembler initialization.

	idnt  Web
	section  one
	--Define macros for assembler	  7 39
	--Define library references	  7 40
	--EQU statements			  7 38

6	Here are some notes on register use:
	   D0 used often
	   D1 used globally during part of input phase for quote flag
	   D2 used globally during part of input phase
	   D3 used globally, usually holds current line length
	   D4 not used
	   D5 not used
	   D6 not used
	   D7 not used
	   A0 used often; used globally in both input and output phases
	   A1 used often; used globally in both input and output phases
	   A2 used globally in input phase to point to parenthesis flag
	   A3 used locally
	   A4 used locally
	   A5 not used
	   A6 used globally; holds AmigaDOS library base pointer

3. The main routine reads input file into a buffer, noting definitions,
then writes buffer to output file, doing requisite processing
dynamically.

Main

 define  push  -(sp).L
 define  pop    (sp)+
 define  chr    D0.B

	--Get file name from command line 	7  4
	--Initialize standard input and output	7 36
	--Open input and output files		7  5

 define  msecttype	  1
 define  csecttype	  2
 define  deftype	  3

 long    fpoint
 long    filebuf
	d0.l  =  # maxfsize
	d1    =  0
	callex   AllocMem
	filebuf  =  d0
	= { d0  =  100
	    rts
	}
	fpoint   =  filebuf


 long    lastsect
	lastsect	=  #sectlist

	--Input the file, noting definitions and trimming comments       7 6
	arg`a  =	ihandle;   call     Close
	--Output the file, substituting appropriately for defined names  7 7
	--Add bss section 					         7 8
	fprint   end.line
	arg`a  =	ohandle;   call     Close

	a1.l  =  filebuf
	d0.l  =  # maxfsize
	callex  FreeMem

	d0    =  0

4. Make a copy of the name in the command tail.  If the name does not end
in '.w', add this.  Use this copy as the input file name.
   Make another copy of this, and change the last letter of the second
copy to 'a', and use this as the output file name.

--Get file name from command line
	a1    =  ^infname
	a2.l  =  a1
next.fname.char
	tst.l    d0
	!=  { d1.b  =  (a0)+
	      d1.b  ?  ' '
	      > +  (a1)+.b  =  D1
		 d0	 -=  1
		 ->  next.fname.char ;
	}
	-2(a1).b	?  '.'
	= +  -1(a1).b  ?	'w'
	     = +	a1 -= 2  ; ;
	(a1)+.b  =  '.'
	(a1)+.b  =  'w'
	clr.b    (a1)

	a1  =  ^outfname
	{  (a1)+.b  =  (A2)+;  bne   }
	-2(a1).b	=  'a'

5. Just AmigaDOS stuff.

--Open input and output files

 define  arg`a  D1.L    7 arguments to AmigaDOS functions
 define  arg`b  D2.L
 long    chandle
 long    ihandle
 long    ohandle

	a1  =  ^infname
	tst.b    (a1)
	beq      abort	7 cf. output section

	arg`a  =	a1
	arg`b  =	#1005
	call     Open
	tst.l    d0
	beq      abort
	ihandle  =  d0

	arg`a  =	#outfname
	arg`b  =	#1006
	call     Open
	tst.l    d0
	beq      abort1	7 cf. output section
	ohandle  =  d0



6. This is the first half of the task.  Names of macro sections and
procedure sections are detected, and their addresses placed in a
table for later use by the output half of the program.

--Input the file, noting definitions and trimming comments
	byte  instatus
	byte  parenstatus
	instatus = 1

	->       next.line
	{  chr  =  (input_line)
	   a2  =	^parenstatus
	define   paren_flag (A2).B
	   --Keep ignoring lines of a comment paragraph	       7 6.1
	   --Examine beginning of input line		       7 6.2
 7 line will now be placed in buffer, probably
	   --Examine each character of input line 	       7 6.3
	   tst.b	  paren_flag	   7 ignore parenthical line
	   = { --Append possible data label		       7 6.4
	       --Move l_length chars from obuf to file buffer  7 6.5
	   }
next.line
	   --Read an input line				       7 22
	   tst.l	  l_length
	   bne   }



6.1 In a comment section, discard everything, but keep looking for
a blank line to terminate the section.

--Keep ignoring lines of a comment paragraph
	tst.b    instatus
	= { chr  ?  new_line
	    bne	   next.line
	    instatus  =  1
	    ->   next.line
	}


6.2 The portion of the input phase syntactic analysis that can be done
on the basis of the first few characters of an input line is done
here.  Also, we make a few adjustments to the beginning of the line:
deleting extra spaces, and left adjusting braces.

--Examine beginning of input line

	chr  ?  new_line	       7 discard blank lines
	beq      next.line
	chr  ?  '*'	 7 line with initial '*' is a comment
	beq      next.line

	chr  ?  '('	 7 line-initial '(' begins a parenthetical
	= {		  7	comment
	paren_flag += 1
	--Trim off first character of input line		7 6.2.1
	  7 remove it from line so that it won't count
	  7  twice when checking parenthesis balance below
	}

 define   tmp_ln   A1.L
	tmp_ln  =  input_line
	--Trim extra initial blanks				7 6.2.2
7 here tmp_ln points to first non-blank character
	--Left adjust braces					7 6.2.3
	--Look for key words					7 6.2.4
	--Check for comment paragraph header			7 6.2.5
7 tmp_ln is no longer correct
	--Check for name of procedure or code section		7 6.2.6


6.2.1  This code is also used below.

--Trim off first character of input line
	input_line	+=  1
	l_length	-=  1

6.2.2  Aside from trimming all but one initial blank, leave tmp_ln
pointing at first non-blank character.

--Trim extra initial blanks
	chr  ?  ' '
	= { { tmp_ln	+=  1
	      (tmp_ln).b	?  ' '
	      bne      '
	      --Trim off first character of input line	 7 6.2.1
	    ->   }
	}

6.2.3  Braces will later be changed to labels.  Eliminate preceding
blank so assembler will recognize them as such.

--Left adjust braces
	(tmp_ln).b  ?  '{'
	beq      is.a.brace
	(tmp_ln).b  ?  #leftg.char
	beq      is.a.brace
	(tmp_ln).b  ?  '}'
	beq      is.a.brace
	(tmp_ln).b  ?  '['
	beq      is.a.brace
	(tmp_ln).b  ?  ']'
	=  {
is.a.brace
	    -1(tmp_ln).b	?  ' '
	    = {  --Trim off first character of input line  7 6.2.1
	    }
	}

6.2.4  If we find a key word, remove the key word, put a null byte before
the defined symbol to signal that this line should not be put out during
output phase, and enter address in the table.

--Look for key words
	byte  defstatus

	tst.b    paren_flag    7 check for '(define...' at beginning of line
	bne      '

	a4    =  ^key.define
	d0    =  6
	Match this key			     7 6.2.4.1
	= + d0 = deftype; -> reference.line ;
	a4    =  ^key.byte
	d0    =  4
	Match this key
	= + d0 = 1; -> data.decl ;
	a4    =  ^key.word
	d0    =  4
	Match this key
	= + d0 = 2; -> data.decl ;
	a4    =  ^key.long
	d0    =  4
	Match this key
	= + d0 = 4; -> data.decl ;
	->  '
data.decl
	defstatus = d0
	d0.w     <<= 8
	d0.b  =  deftype
	->  reference.line

6.2.4.1  If the key matches, adjust the line by removing the key and
marking the line with a nul.

Match this key
	a3.l  =  tmp_ln
	d2    =  d0
	{ (a4)+.b  ?  (a3)+
	  dbne	 d0,}
	= { d0.l	=  tmp_ln
	    d1.l	=  input_line
	    d0.l	-=  d1
	    d0		+=  d2
	    { (a3)+.b  ?	' '
	      bne      6
	      d0	+=  1
	    ->   }
	    a0.l	+= d0
	    l_length	-= d0
	    (input_line).b =  0
	}


6.2.5  Comment sections are introduced by ''', '6', or by a number and '.';
  any of these may be preceded by blanks.  If we see one of these, reset
  instatus flag.

--Check for comment paragraph header
	chr  =  (tmp_ln)+
	chr  ?  #para.char
	beq      now.commenting
	chr  ?  #section.char
	beq      now.commenting
	Is it a digit?
	= { { chr  =  (tmp_ln)+
	      Is it a digit?
	      beq   }
	    chr  ?  '.'
	    = {
	now.commenting:
	    7 Remember that we are in a comment section.
	      instatus  =  0
	      ->	next.line
	    }
	}

6.2.6  If we find a section name, put its address in the table.

--Check for name of procedure or code section
	tst.b    paren_flag
	bne      '

	 7 Check for name of a procedure section.
	chr  =  (input_line)
	Is it a capital?
	= + d0.w	=  csecttype; ->  section.reference ;

	 7 Check for name of a macro section.
	(input_line).b  ?  '-'
	= { 1(input_line).b  ?  '-'
	    = { d0.w  =  msecttype
  section.reference:
	        a1    =  ^branch.stack
	        a1.l  ?  brace.level
	        != { brace.level.l = a1
		   --Warn about unmatched brace 	       7 6.2.6.1
	        }
	        sect.name.l = fpoint
	        sect.namelen.b = l_length
  reference.line:		  7 branch to here from 6.2.4
	        --Enter in table			       7 6.2.6.2
	    }
	}

6.2.6.1  Error message to standard output.

--Warn about unmatched brace
	movem.l  d0-d3/a0,-(sp)
	print    brace.prob
	arg`a	=	chandle
	clr.l    l_length
	l_length.b  =  sect.namelen
	arg`b	=	sect.name
	call     Write
	movem.l  (sp)+,d0-d3/a0


6.2.6.2 The current place in the file buffer is where the input line
we are working on will be placed.  Enter this into the table, with
entry type passed in d0.

--Enter in table
	a1.l	  =  lastsect
	(a1)+.l	  =  fpoint
	(a1)+.w	  =  d0
	lastsect  =  a1

6.3  Various special characters in the input line trigger web
transformations.

--Examine each character of input line
 define   quote_flag  D1
	quote_flag    =  0
	 7 count of characters in line to examine
 define   char_count  D2.L
	char_count  =  l_length
	tmp_ln  =  ^obuf
	clr.b    -1(tmp_ln) 7 guard byte when search backwards
	->    next.character
  no.put.character:
	l_length -= 1
	->       next.character
{
 is.it    ''''; =  +  eor.b	#1,quote_flag  ; 7 enclosed in quotes?
 tst.b    quote_flag
 = {   7 This part of line is not within quotes.
	is.it    ';';  = +  chr	=  new_line;  -> put.character ;
	--For blank, ignore if redundant		       7 6.3.1
	--For bullet character, strip end of line 	       7 6.3.2
	--For grouping characters, substitute labels	       7 6.3.3
	--For parentheses, keep track of nesting	       7 6.3.4
	--For colon, left adjust label and start new line      7 6.3.5
 }
 put.character:
 tst.b    paren_flag; bne   no.put.character
 (tmp_ln)+.b  =  chr
next.character
 chr  =  (input_line)+; char_count -= 1
 bpl      }
.end.6.3

6.3.1 Strip off extra white space.  Note that tabs in input file have been
converted to blanks already.

--For blank, ignore if redundant
	is.it   <' '>;   bne	'
	(input_line).b  ?  ' '
	beq    no.put.character


6.3.2  Discard what is after the end-line comment character, and
trim any preceding blanks.

--For bullet character, strip end of line
	--Other characters treated as bullets
	is.it    bullet.char
	= { l_length -=  char_count
	    char_count  =  l_length
	    {  char_count -= 1
	        7 If line has become empty, ignore it altogether.
	       beq      next.line
	       (tmp_ln).b  =  new_line
	       chr  =  -(tmp_ln)
	       is.it    <' '>
	       bne      .end.6.3
	       l_length -= 1
	       ->  }
	}


--Other characters treated as bullets
	chr  ?  'A' + 128;	bcs	'
	chr  ?  'Z' + 128;	bhi	'
	chr  =  # bullet.char



6.3.3  In addition to labels, insert newlines for '+','{', and ';'. Place
an additional break label on the line after '}', and when we see '6',
substitue this label.

--For grouping characters, substitute labels
	tst.b    paren_flag
	bne      '

	   byte bracket_flag
	bracket_flag  =  0

	is.it    leftg.char
	beq      begin.group
	is.it    '['
	= {	bracket_flag	=  1
	  	->   begin.group
	}

	is.it    rightg.char
	= {	(tmp_ln)+.b  =	new_line
		l_length  += 1
		->	 end.group
	}

	is.it    '{'
	= {
 begin.group:
	  Another left adjustment     7 6.3.3.1
	  Push brace level	    7 28
	  Generate branch label	    7 32
	  bracket_flag  =  0
	  (input_line).b	?  new_line
	  beq	 no.put.character
	  chr  =	new_line
	  ->    put.character
	}
	is.it    ']'
	= { bracket_flag	=  1
	    ->   end.group
	}
	is.it    '}'
	= {
 end.group:
	  Another left adjustment	7 6.3.3.1
	  Pop brace level		7 29
	  Generate branch label		7 32
	  tst.b  bracket_flag
	  != { bracket_flag  =  0
	       -> no.put.character
	  }
	  (tmp_ln)+.b  =	new_line
	  l_length += 1
	  --Get last break label	7 31
	  Generate branch label		7 32
	  ->  no.put.character
	}

	is.it    para.char
	= { --Get break label		7 30
	    Generate branch label	7 32
	    ->  no.put.character
	}

6.3.3.1  Labels from braces at the beginning of a line will not be left
adjusted after newlines due to ':', ';', or another brace, unless we
make this special adjustment.   When the first preceding non-blank is
other than a newline, we don't want an adjustment, so the saved values
of l_length and tmp_ln are restored.  But when it is newline, we
discard the following blanks.

Another left adjustment
	movem.l  l_length/tmp_ln,-(sp)
more.left
	chr  =  -1(tmp_ln)
	chr  ?  new_line;   = + a7  +=  8; ->  ' ;
( Have to use a7 above, not sp, to get an addq. )
	chr  ?  ' '
	= { tmp_ln	-= 1
	    l_length	-= 1
	    ->	   more.left
	}
	movem.l  (sp)+,l_length/tmp_ln

6.3.4  The only thing special here is to watch for the right paren that
closes out the comment, and make sure to discard it.  It's not important,
but in case nothing follows on the line, we also avoid storing a blank
line.

--For parentheses, keep track of nesting
	tst.b    paren_flag
	beq      '
	is.it    '(';   =  +  paren_flag += 1 ;
	is.it    ')'
	bne      '
	paren_flag  -= 1
	bne      no.put.character
	(input_line).b  ?  new_line
	beq      next.line
	->       no.put.character

6.3.5  In output phase, it is convenient to be able to distinguish
labels just by whether the line starts with a space.  The BS character
will not be put in the file buffer.

--For colon, left adjust label and start new line
	tst.b    paren_flag
	bne      '

	is.it    ':'
	bne      '
	obuf.b  ?  ' '
	= +  obuf.b  =  8  ;
	(input_line).b  ?  new_line
	beq      no.put.character
	(tmp_ln)+.b  =  new_line
	l_length += 1

	(input_line).b  ?  ' '  7 make sure of space after colon
	beq      no.put.character
	chr  =  ' '
	->   put.character

6.4  If a data declaration was detected, append a generated label
to add to the definition.

--Append possible data label
 word  declcount
	chr  =  defstatus
	beq   '
	tmp_ln -= 1    7 replace newline with blank
	(tmp_ln)+.b = ' '
	a3    = ^declcount
	d0.w  =  (a3)
	(a3).w += 1
	Generate branch label	 7 32
	(tmp_ln)+.b = 'Q'
	(tmp_ln)+.b = '.'
	chr  =  defstatus
	is.it  1; = + (tmp_ln)+.b = 'B' ;
	is.it  2; = + (tmp_ln)+.b = 'W' ;
	is.it  4; = + (tmp_ln)+.b = 'L' ;
	(tmp_ln)+.b  =  new_line
	l_length	 += 4
	defstatus   = 0


6.5  A string copy routine.	Skips an initial BS which is used to
left adjust labels.

--Move l_length chars from obuf to file buffer
	a1.l    =  fpoint
	a0      =  ^obuf
	(a0).b  ?  8
	= + l_length -= 1; a0 += 1 ;
	l_length -= 1
	bmi      '
	{  (a1)+.b  =  (a0)+
	   dbra	  l_length,}
	fpoint  =  a1





7. This is the second half of the task.  We take each procedure that
was noted in in the input phase and put it out.  Macro sections are
thus skipped over, but they will be included where they are invoked
by the recursive subroutine 'Output section ...'.

--Output the file, substituting appropriately for defined names
 define   t_entry	A1.L
	t_entry		=  lastsect
	clr.l    (t_entry)   7 in case later decide to use alloc to get mem
	t_entry		=  ^sectlist
	lastsect	=  t_entry
 define  p_buffer	A0.L
	p_buffer	=  filebuf
 define  sect_count D3.L
	sect_count  =  0
 word    bracecount
	bracecount  = 1
 word    bracketcount
 word    typeofsect

next.sect
	push	=  sect_count
	Push brace level	   7 28
	Output section starting at p_buffer in filebuf	 7 7.1
	Pop brace level	   7 29
	sect_count  =  pop

	{	tst.l    (t_entry)
		beq      '
		p_buffer	=  (t_entry)+
		d0.w		=  (t_entry)+
		d0.w  ?  csecttype
		bne      }
	typeofsect	=	d0
	lastsect	=	t_entry
	sect_count	+=	1
	movem.l  sect_count/p_buffer,-(sp)
	--Generate procedure label	    7 27
	movem.l  (sp)+,sect_count/p_buffer
	Find registers to save
	bra      next.sect

abort1
	arg`a  =	ihandle
	call     Close
abort
	print    nogo
	d0  =  10
	rts


Find registers to save
	long	saveregs

	clr.l	saveregs
	{	chr	=	(p_buffer)+
		chr  ?  new_line;	beq	6
		chr  ?  '('
		= {  {	chr  =	(p_buffer)+
			chr  ?	'('
			= {	{  (p_buffer)+.b  ? ')'
				   bne	}
				chr  =	(p_buffer)+
			}
			chr  ?  ')'
			= {	(p_buffer).b  ?	new_line
				= {	p_buffer  +=	1
					->	'
				}
				push	=	sect_count
				saveregs  =	p_buffer
				Move line at p_buffer in file buffer to obuf
				push	=	p_buffer
				Do substitution for defined symbols
				Purge length suffixes
				push	=	l_length
				fprint	moveminst
				l_length  =	pop
				a0	=	^ obuf
				(a0).b  ?  9
				= {	a0  +=	1
					l_length  -=	1
				}
				arg`a	=	ohandle
				arg`b	=	a0
				l_length  -=	1
				call	Write
				fprint	pushsuffix
				p_buffer  =	pop
				sect_count  =	pop
				->	'
			}
		     ->	   }
		}
		->   }


7.1. Detect procedure and macro invocations.  For procedures, we generate
a 'bsr' instruction.  For macros, we redirect the buffer pointer to
where the macro definition is and do a recursive call.

Output section starting at p_buffer in filebuf
7 branch to here from 7.1.2
outsect
	t_entry  =  lastsect
	p_buffer	?  fpoint
	bcc      done.sect
7 look for next section, past any defines in table
	{	5(t_entry).b  ?  deftype
		bne      6
		t_entry += 6
		bra   }
7 if doing last section, continue to end of file
	tst.l    (t_entry)
	beq      this.sect
7 have we gotten to beginning of next section?
	p_buffer	?  (t_entry)
	bcs      this.sect
done.sect
	--Generate end section label     7 24
	d0  =  0
	rts

this.sect
	Move line at p_buffer in file buffer to obuf	   7 7.1.1
	chr  =    obuf
	  7 ignore 'define' lines (which were marked with nul)
	beq	outsect
	chr  ?  new_line
	beq	outsect

	push  =  p_buffer 7 save point to next line

	 7 check for macro call
	tmp_ln  =  ^obuf
find.end.label
	chr  =  (tmp_ln)+
	chr  ?  ' '
	!= { chr	?  new_line
	     bne	find.end.label
	}
	chr  ?  ' '
	= { d2	=   csecttype
	    chr  =   (tmp_ln)
	    Is it a capital?     7 If so, we have a procedure call
	    beq	   embedded.sect

	    (tmp_ln).b  ?  '-'
	    = { 1(tmp_ln).b  ?  '-'
	        = { d2  =  msecttype
	 embedded.sect:
		  push.w  =  typeofsect
		  push	  =  lastsect
		  push	  =  saveregs
		  Push brace level     7 28
		  Find and output macro section 	   7 7.1.2
		  Pop brace level      7 29
		  saveregs  =  pop
		  lastsect  =  pop
		  typeofsect  = pop
		  p_buffer  =  pop
		  ->   outsect
	        }
	    }
	    push	=  tmp_ln
	    --Do substitution for branch symbols	   7 7.1.3
	    tmp_ln  =  (sp)
	    Do substitution for defined symbols 	   7 7.1.4
	    tmp_ln  =  pop
	    --Rearrange statements with an equals sign	   7 7.1.5
	}
	Purge length suffixes				   7 7.1.6
	arg`a  =	ohandle
	arg`b  =	#obuf
	call     Write
	p_buffer	=  pop

	l_length	?  d0
	beq      outsect	7 loop for next line
7 sure hope we don't get to here
	print    prob
	d0  =  10


7.1.1  A string copy routine.  This also handles substitution of
label for ''' as target of branch.

Move line at p_buffer in file buffer to obuf
	l_length	=  0
	a1	=  ^obuf
	{  chr	   =  (p_buffer)+
	   (a1)+.b   =  chr
	   l_length += 1
	   chr  ?  new_line
	   bne	  }
	a1 -= 1
	{  -(a1).b  ?  ' '
	   bne	  6
	   l_length -= 1
	   (a1).b  =  new_line
	   ->    }
	(a1).b  ?  #section.char
	= { l_length -= 1  7 for losing section char
	    --Append end section label   7 25
	}

7.1.2  Action when procedure or macro invocation is detected.

Find and output macro section
	sect_count  =  0
	d1.l	  =  tmp_ln
	t_entry	  =  ^sectlist
 {
	{ tst.l	 (t_entry)
	  = + push	=  d1
	      print    what.mac
	      tmp_ln	=  pop
	      --Tell the bad name
	      d0	=  10
	      rts ;
	  p_buffer  =  (t_entry)+
	  d0.w	    =  (t_entry)+
	  d0.w  ?  d2  7 secttype passed by caller
	  =   }
	sect_count += 1
	lastsect	=  t_entry
	a2.l  =  d1
	{ chr  =	(p_buffer)+
	  chr  ?	new_line
	  != +  chr  ?  '('  ;
	  = {   chr  ?  (a2)
	        beq      c.m.match
	  }
	  chr  ?	(a2)+
	  beq	 }
 ->    }

c.m.match
( If chr is '(', put out = stmts.  Parameter list
  is at p_buffer, and arg list is at a2+1 in obuf.)

	chr  ?  '('
	= + --Arguments to parameters  ;

	d2.w  ?  msecttype
	= {	typeofsect = d2
		p_buffer  -= 1
		Find registers to save
		->	outsect
	}
	d2.w  ?  csecttype
	= { --Generate BSR procedure label  7 23
	    d0  =  0
	    rts
	}
	7 stub other sector types
	d0  =  0



( If chr is '(', put out = stmts.  Parameter list
  is at p_buffer, and arg list is at a2+1 in obuf.)

--Arguments to parameters
	a2	+=	1
	(a2).b	?	')';	beq	'
	push	=	p_buffer
	push	=	d2
	push	=	sect_count
	push	=	p_buffer
7 strip name from procedure call
	p_buffer  =	a2
	Move line at p_buffer in file buffer to obuf
        Do substitution for defined symbols
	Purge length suffixes
7 save in ibuf
	source_s  =	^ obuf
	target_s  =	^ ibuf
	l_length -=	1
	{	(target_s)+.b	=  (source_s)+
		dbra	l_length,}

7 strip off name from procedure header
	p_buffer  =	pop
	Move line at p_buffer in file buffer to obuf
        Do substitution for defined symbols
	Purge length suffixes
7 generate moves from list of args in ibuf to list of parms in obuf
	--Moves from args to parms
	sect_count  =	pop
	d2.l	=	pop
	p_buffer  =	pop


--Moves from args to parms
	source_s  =	^ ibuf
	target_s  =	^ obuf
	{	(source_s).b  ?	')';	beq	'
		(target_s).b  ?	')';	beq	'
		7 How long is parm?
		Measure length of list item(target_s)
		push	=	tmp_ln
		d1.l	=	l_length
		Measure length of list item(source_s)
		push	=	tmp_ln
		tst.l	l_length
		> {	tst.l	d1
			> {	push	=	target_s
				push	=	d1
				push	=	source_s
				push	=	l_length
				fprint	moveinst
				l_length  =	pop
				arg`b	=	pop
				arg`a	=	ohandle
				call	Write
				fprint	commachar
				l_length  =	pop
				arg`b	=	pop
				arg`a	=	ohandle
				call	Write
				fprint	newlinechar
			}
		}
		source_s  =	pop
		target_s  =	pop
		->	}

Measure length of list item(tmp_ln)
	l_length  =	0
	{	chr	=	(tmp_ln)+
		chr  ?  '('
		= {	{	l_length  +=	1
				(tmp_ln)+.b  ?  ')'
				bne	}
7			l_length  +=	1
7			chr	=	(tmp_ln)
		}
		chr  ?	',';	beq	'
		chr  ?	')'
		= {	tmp_ln  -=	1
			->	'
		}
		l_length  +=	1
		->	}


( s. 7.1.3 is below )

7.1.4  The line in obuf is just about to be written to output file.  Here
we want to make substitutions for define's that were found in the
input phase.

Do substitution for defined symbols
(l_length is in use now.)
 define   target_s  A0.L
	target_s	  =  ^obuf
	quote_flag  =  0
look.for.symbol
	{  chr  =  (target_s)+
	   chr  ?  new_line
	   beq	  '
	   is.it	  ''''
	   = +  eor.b  #1,quote_flag ;
	   tst.b	  quote_flag
	   bne	  }
	is.it    '_'
	bcs      look.for.symbol
	is.it    'z'
	bhi      look.for.symbol
	target_s -= 1
	--Try to find symbol in table 7 7.1.4.1
	!=  {
	    --Do the substitution     7 7.1.4.2
	}

	{ quote_flag  =  0
	  chr  =	(target_s)+
	  chr  ?	new_line
	  beq	 '
	  is.it	 ''''
	  = +  eor.b  #1,quote_flag; -> look.for.symbol ;
	  is.it	 '_'
	  bcs	 look.for.symbol
	  is.it	 'z'
	  bhi	 look.for.symbol
	  ->   }


7.1.4.1  Go through table and try to match each symbol name of each
definition.  If matched, return condition code 'not equal', and source_s
pointing at beginning of definition.

--Try to find symbol in table
(target_s points to the candidate symbol.)
 define  source_s	A2.L
 define  defn_type	D2
	defn_type  =  deftype

	t_entry	 =  ^sectlist
   {
try.next.entry
	{	tst.l	 (t_entry)
		beq	 '     7 sym.not.there
		source_s  =  (t_entry)+
		d0.w  =  (t_entry)+
		d0.b  ?  defn_type
		bne	 }

	source_s += 1   7 skip the 0 byte
	a3.l  =  target_s

	{	chr  =	(source_s)+
		chr  ?	' '  7 end of reference symbol?
		!= [	chr  ?  (a3)+
			beq	}
		->	try.next.entry
		]
	chr  =  (a3)
	chr  ?  '_'
	bcs	6
	chr  ?  'z'
	bhi	6
   ->    }	   7 try next entry

7 point source_s past any spaces

	{	(source_s).b  ?  ' '
		bne	6
		source_s += 1
		->	}

  7 condition flag is not equal here



7.1.4.2  Substitute in obuf the symbol pointed to by source_s for the symbol
pointed to by target_s.  The new source_s text ends with newline, while the
old target_s text ends with a non-lower-case-alphabetic.
  target_s is left pointing at the new text, and l_length is
adjusted for the new length.

--Do the substitution
7 What is length of new text?
	d1     =	-1
	a3.l   =	source_s
	{ d1  +=	1
	  (a3)+.b  ?  new_line
	  bne   }
7 What is length of old text?
	d2    =  -1
	a1.l  =  target_s
	{ d2   +=  1
	  chr  =	(a1)+
	  Is it an alphabetic?	 7 7.1.4.2.1
	  beq   }
7 How much longer is the new text?
	d0.l  =  d1
	d0.l -=  d2
 !={
	+ {
	  7 It is longer, so make more room.
	    7 Where is end of line?
	  a1    =  ^obuf
	  a1.l +=  l_length   7 a1 points 1 beyond end
	  a3.l  =  a1
	  a3.l +=  d0    7 1 past new end
	  { -(a3).b  =  -(a1)
	    target_s  ?  a1
	    bne	}
	  ->  done.length.adjust
	  }
	7 It is shorter, so shorten old text
	a1   -=  1	7 back to 1st char after old text
	a3.l  =  a1
	a3.l += d0    7 1st position after new text
	{ (a3)+.b  =  (a1)+
	  -1(a1).b  ?  new_line
	  bne   }
 }
done.length.adjust

	l_length += d0	7 new length
7 copy in new text: length is in D1
	a1.l  =  target_s
	d1   -= 1
	+ {
	  { (a1)+.b  =  (source_s)+
	    dbra	   d1,}
	}
  7 in case substitute text begins with a defined symbol, here we will
  7 point back to preceding non-alphabetic, so main routine will not
  7 skip over it
  target_s -= 1


7.1.4.2.1 Test for lower case alphabetic in d0, returning conclusion as
condition code 'equal' if it was.

Is it an alphabetic?
	chr  ?  '_';  bcs   '
	chr  ?  'z';  bhi   '
	chr  ?  chr


7.1.3  Look through table to see if line begins with '=', '<=', etc.
If so, get branch mnemonic from table and substitute it.

--Do substitution for branch symbols
 define br_len D2
	a2  =  ^branch.table
	bra      next.branch.entry
	{  br_len  =  1
	   chr  ?  (tmp_ln)
	   = { chr  =  1(A2)
	       beq     matching.branch
	       br_len  =	2
	       chr  ?  1(tmp_ln)
	       = { chr  =  2(A2)
		 beq	 matching.branch
		 br_len  =  3
		 chr  ?  2(tmp_ln)
		 = {
	 matching.branch:  --Substitute branch mnemonic 7 7.1.3.1
			 ->  '
		 }
	       }
	   }
	   a2  +=  6
next.branch.entry
	   chr  =  (a2)
	   bne   }


7.1.3.1  Replace special branch symbol in obuf at position tmp_ln with
regular mnemonic in table, which is offset 3 bytes from the
beginning of the entry. Pointer to entry was left in A2 by search
routine, and br_len has length of special symbol.

--Substitute branch mnemonic
	d0     =	4	7 amount extra room needed
	d0.l  -=	br_len
	a0     =	^obuf
	a0.l  +=	l_length   7 one beyond end of line
	l_length += d0
	a3.l   =	a0
	a3.l  +=	d0	 7 new end of line
	{  -(a3).b  =  -(a0)
	   a0.l	  ?  tmp_ln
	   bne   }
	(tmp_ln)+.b  =  3(A2)
	(tmp_ln)+.b  =  4(A2)
	(tmp_ln)+.b  =  5(A2)
	(tmp_ln)+.b  =  ' '


7.1.5  Change 'a = b' to 'move b,a', etc.

--Rearrange statements with an equals sign
	a3.l		=  tmp_ln
	source_s	=  ^ibuf
	quote_flag	=  0
	target_s	=  quote_flag
	{  chr  =  (tmp_ln)+
	   is.it	  ''''
	   =  +  eor.b	#1,quote_flag ;
	   tst.b	  quote_flag
	   =  {  is.it	'?'
	         != +  is.it  '='  ;
	         =  +  target_s  =  source_s ;
	         is.it	<' '>
	         =  +  chr  =  -(source_s) ;
	   }
	   (source_s)+.b	=  chr
	   chr  ?  new_line
	   bne	  }
	tmp_ln  =  a3
	clr.b    -1(source_s)
	d0.l  =  target_s
	!= { --Do the rearrangement      7 7.1.5.1
	}

7.1.5.1  Copy to obuf the mnemonic, then the source, then the destination

--Do the rearrangement
	--Point source_s at correct mnemonic	7 7.1.5.1.1
	{ (tmp_ln)+.b  =	(source_s)+;  bne  }
	tmp_ln  -=  1
	--Attach length suffix			7 7.1.5.1.2
	(tmp_ln)+.b  =  ' '
	clr.b    (target_s)+
	--Find start of second operand		7 7.1.5.1.3
	--Detect literal operand			7 7.1.5.1.4
	{ (tmp_ln)+.b  =	(target_s)+;  bne  }
	-1(tmp_ln).b  =  ','
	source_s	=  ^ibuf
	{ (tmp_ln)+.b  =	(source_s)+;  bne  }
	-1(tmp_ln).b  =  new_line
	source_s	    =  ^obuf
	tmp_ln	   -= source_s
	l_length	    =  tmp_ln

7.1.5.1.1  Look at characters before and after the '=' to decide.

--Point source_s at correct mnemonic
	source_s	     =	^mnem.move  7 initial assumption
	1(target_s).b  ?	'&'
	!= + 1(target_s).b  ?  '^' ;
	=  +  source_s  =  ^mnem.lea; -> '  ;
	(target_s).b   ?	'?'
	=  +  source_s  =  ^mnem.cmp; -> '  ;

	chr  =  -1(target_s)
( What to do about signed multiply and divide? )
	is.it  '*'; = + source_s = ^ mnem.mulu; -> k.ob. ;
	is.it  '/'; = + source_s = ^ mnem.divu; -> k.ob. ;
	is.it  '&'; = + source_s = ^ mnem.and;  -> k.ob. ;
	is.it  '|'; = + source_s = ^ mnem.or;   -> k.ob. ;
( Use <<= and >>= here.  Should there
  be a convention for asl/asr? Rotate instructions? )
	is.it  '<'; = + source_s = ^ mnem.lsl; clr.b  -(target_s);  -> k.ob. ;
	is.it  '>'; = + source_s = ^ mnem.lsr; clr.b  -(target_s);  -> k.ob. ;

	7 test for +=/-=
	-2(target_s).b  ?  ')'; beq  '  7 '+' after ')' must be post increment
	is.it    '+'
	=  +  source_s  =  ^mnem.add; -> chk.long.as ;
	is.it    '-'
	=  +  source_s  =  ^mnem.sub; -> chk.long.as ;
	-> '
chk.long.as
	7 does it have arg from 1 to 8?
	chr = 2(target_s)
	chr  ?  '('; beq	k.ob.  7 no addq/subq if indirect register ref.
	Is it a digit?	7 if so, out of range
	!= +  chr = 1(target_s)
	      chr ? '1'
	      >= + chr ? '8'
		 <= + source_s += 4 ; ; ; 7 point to 'q.l' version
k.ob.
	target_s -= 1  7 discard '+', '-', etc.


7.1.5.1.2  A length suffix on the first operand gets put onto the
instruction mnemonic.

--Attach length suffix
	-2(target_s).b  ?  '.'; bne '

	-2(tmp_ln).b ? '.'  7 replace '.l' if add/sub
	= + tmp_ln -= 2 ;
	(tmp_ln)+.b  =  '.'
	chr   =  -1(target_s)
	bset  #5,chr
	(tmp_ln)+.b  =  chr
	clr.b    -2(target_s)

7.1.5.1.3  The previous analysis may have moved us back a little.  Now
get back to the '=', and ignore any following pointer mark.

--Find start of second operand
	chr  =  (target_s)
	=  +   target_s += 1; chr  =  (target_s)	;
	is.it    '='
	=  +   target_s += 1; chr  =  (target_s)	;
	is.it    '&'
	!= + is.it    '^' ;
	=  +   target_s += 1  ;

7.1.5.1.4  Decide whether to stick in a '#', and also see if it's ok to
use moveq instead of move.

--Detect literal operand
	is.it    '''';  beq  .lit.add
*	 is.it	'$' ;  beq  .lit.add
* Not before $ is inconsistent, but I have too much code that
* uses hex register offsets ...

	is.it    '@' ;  beq  .lit.add
	is.it    '%' ;  beq  .lit.add

	source_s	= target_s
	is.it    '-'
	=  +  source_s += 1; chr = (source_s) ;
	--Is it just a number?
	=  {  chr  =  -2(target_s)
	      d2.b =  -3(target_s)
	      is.it 'L'
	      = { tst.b  -3(target_s)
		= { chr  = -4(target_s)
		    d2.b = -5(target_s)
		    bclr  #5,d2
		    d2.b  ?  'D'
		    = { Is it a digit?
			= { -4(tmp_ln).b  ?  'e'
			    = + tmp_ln -= 2 ;
			}
		     }
		}
	      }
	      bclr  #5,d2
	      d2.b  ?  'D'; bne .lit.add
	      -2(tmp_ln).b  ?  'e'; bne .lit.add	7 test for move mnemonic
	      Is it a digit?
	      =  +  -1(tmp_ln).b	=  'q';  (tmp_ln)+.b  =  ' '  ;
	       7 Above is not sufficient test for reference to data reg!
	       7 .. could be symbol ending in 'd' + digit
	  .lit.add:
	      (tmp_ln)+.b  =  '#'
	}

--Is it just a number?
	Is it a digit?
	bne   '
	source_s += 1
	{  chr = (source_s)+
	   Is it a digit?
	   beq   }
	chr  ?  '('
	= + tst.b  chr; -> ' ;
	chr  ?  chr

7.1.6  Elide all occurrences of '.B', '.W', and '.L'.

Purge length suffixes
	tmp_ln   =  &obuf
	source_s	=  tmp_ln
	quote_flag  =  0
	{	d2.b  =  (source_s)+
		d2.b  ?  '''';  =  +  eor.b    #1,quote_flag ;
		tst.b    quote_flag
		= {	d2.b	?  ' '
			= {	d2.b	=	9
				[  (source_s).b ? ' ';  bne  6
				   source_s  +=  1
				   ->  ]
			}
			d2.b	?  '.'
			= {	chr  =  (source_s)
				Is it a length?	       7 7.1.6.1
				= {	source_s += 1
					d2.b	    = (source_s)+
					l_length -= 2
				}
			}
		}
		(tmp_ln)+.b = d2
		d2.b  ?  new_line
		bne   }


7.1.6.1

Is it a length?
	chr  ?  'B'; beq '
	chr  ?  'W'; beq '
	chr  ?  'L'



8.  Go through the table and print out DS directives for entries that were
left by data declarations.  Do the 'byte' declarations last, so we will
get word alignment for the others.

--Add bss section
	fprint	 titl.bss
	d2    =  4
 {
	t_entry	 =  ^sectlist
 { { { tst.l    (t_entry)
	    beq	   nxt.bs
	    source_s  =  (t_entry)+
	    d0.w	=  (t_entry)+
	    d0.b	?  deftype
	    bne	   }
	  d0.w  >>= 8
	  d0.w  ?  d2
	  bne    }
	{ (source_s)+.b  ?  ' '; bne }

	target_s	=  ^obuf
	a3.l	=  target_s
	{  chr   =  (source_s)+
	   (target_s)+.b = chr
	   chr  ?  new_line
	   bne   }
	target_s -= 3
	chr	=  1(target_s)
	(target_s)+.b  =	' '
	(target_s)+.b  =	'D'
	(target_s)+.b  =	'S'
	(target_s)+.b  =	'.'
	(target_s)+.b  =	chr
	(target_s)+.b  =	' '
	(target_s)+.b  =	'1'
	(target_s)+.b  =	new_line
	target_s -   = a3
	l_length	   = target_s
	target_s	   = ^-1(a3)
	(target_s).b = l_length
	push	   = t_entry
	push	   = d2
	Put line to output file	 7 35
	d2.l	   = pop
	t_entry	   = pop
	->   }
nxt.bs
	d2.b  >>=  1
	bne  }



( reserve '9-'19 for expansion )

20. Test for digit in chr, returning conclusion as condition code 'equal'
if it was a digit.

Is it a digit?
	chr  ?  '0'; bcs '
	chr  ?  '9'; bhi '
	chr  ?  chr

21. Test for capital letter in chr, returning conclusion as condition
code 'equal' if it was one.

Is it a capital?
	chr  ?  'A'; bcs '
	chr  ?  'Z'; bhi '
	chr  ?  chr



22. Fill the input buffer, and return lines from it until there are
no more complete lines.  Then move the last partial line back,
fill the input buffer, and so on.

--Read an input line

	define   input_line   A0.L
	define   l_length     D3.L
	define   new_line     #10
	byte     bufchcount

	input_line  =  bufptr
	push	 =  input_line
	l_length =  0	       7 no chars in line yet
7 back to here when was necessary to read more from file
.rdln.cont
	d2    =  0
	d2.b  =  bufchcount
	bmi      rdln.keep.info	      7 this means file is exhausted
	beq      .rdln.more

	d2.b -= 1
	+ chr  =	(input_line)+
	  chr  ?	new_line
	  beq	 rdln.keep.one
	  chr  ?	9
	  = + -1(input_line).b = ' ' ;
	  l_length   +=  1
	  l_length.b  ?  #ibufLen
	  beq	 rdln.keep.info
	  dbra	 D2,}
7 ran out of chars -- go get more
	bra      .rdln.more
7 have one line -- check not empty
rdln.keep.one
	l_length += 1
rdln.keep.info
	bufptr.l	    =  input_line
	bufchcount    =  d2
	input_line  =  pop
	->     '

.rdln.more
7 have partial line in buffer with l_length chars in it
	a1.l     =  pop	 7 beginning of partial line
7 while l_length > 0 move chars back to beginning of buffer
	input_line  =  ^ibuf
	push  =  input_line    7 for ret.
	push  =  l_length
	l_length.b -= 1
	     7 if line was of > 0 length
	+ {
	+ (input_line)+.b  =  (a1)+
	  dbra	 l_length,}
	  }
7 fill remainder of buffer with 80-(l_length) chars
	l_length	=  # ibufLen
	d0.l	  =  pop
	l_length.b -= d0
	push	  =  d0

	a1	  =  ^ibuf
	a1.l	 += d0
7 save where to continue processing line
	push	  =  a1

	arg`a  =	ihandle
	arg`b  =	a1
	call     Read

	tst.b    d0
	= +  st  d0  ;
	bufchcount    =  d0

	input_line  =  pop    7 continue processing here
	l_length	  =  pop    7 chars scanned so far
	bra      .rdln.cont


23. Used during output phase when a procedure invocation is detected.

--Generate BSR procedure label
	a0  =  ^obuf
	(a0)+.b  =  9
	(a0)+.b  =  'b'
	(a0)+.b  =  's'
	(a0)+.b  =  'r'
	(a0)+.b  =  9
	(a0)+.b  =  'P'
	olen.b   =  5 + 1 + 4 + 1
	Binary to hex string	 7 33
	a0       =  ^olen
	Put line to output file	 7 35

24. Label goes at end of every section to serve as target for possible
branch to ' statements.

--Generate end section label
	push     =  a1
	Get current section number 7 26
	d3.w     =  d0
	a0       =  ^obuf
	(a0)+.b  =  'S'
	olen.b   =  1 + 4 + 1
	Binary to hex string	 7 33
	a0       =  ^olen
	Put line to output file	 7 35

	d0.l	=	saveregs
	!= {	push	=	d0
		fprint	moveminst
		fprint	popprefix
		p_buffer  =	pop
		Move line at p_buffer in file buffer to obuf
		Do substitution for defined symbols
		Purge length suffixes
		a0	=	^ obuf
		(a0).b  ?  9
		= {	a0  +=	1
			l_length  -=  1
		}
		arg`a	=	ohandle
		arg`b	=	a0
		call	Write
	}

	d0.w     =  typeofsect
	d0.w  ?  csecttype
	= +	fprint	rtsinst	;

	a1.l  =  pop


25. Corresponding to above label at end of section, when we see a '
character at end of line, substitute a label.

--Append end section label
	Get current section number 7 26
	push     =  a1
	Generate branch label	 7 32
	a1.l     =  pop
	(a1).b   =  'S'

26. Glance at stack for number to use in constructing label.

Get current section number
	push   =	a0
	a0.l   =	brace.level
	d0.w   =	(a0)
	a0.l   =	pop

27. Called during output phase when procedure name -- beginning of
section -- is detected.

--Generate procedure label
	a0       =  ^obuf
	(a0)+.b  =  'P'
	olen.b   =   1 + 4 + 1
	Binary to hex string	 7 33
	a0       =  ^olen
	Put line to output file	 7 35

28. At left brace (input phase) or beginning of section (output phase)
bump and push the current number, so can later construct corresponding
label at matching right brace or end of section.

Push brace level
	push     =  a0
	tst.b  bracket_flag
	!= { a0	    =  ^bracketcount
	     (a0).w  += 1
	     d0.w     =  (a0)
	     a0.l     =  bracket.level
	     -(a0).w  =  d0
	     bracket.level.l  =  a0
	     a0.l     =  pop
	     ->  '
	}
	a0       =  ^bracecount
	(a0).w  += 1
	d0.w     =  (a0)
	a0.l     =  brace.level
	-(a0).w  =  d0
	brace.level.l  =	a0
	a0.l     =  pop

29. Now we need it.

Pop brace level
	push     =  a0
	tst.b  bracket_flag
	!= { a0.l     =  bracket.level
	     d0.w     =  (a0)+
	     bracket.level.l  =  a0
	     a0.l     =  pop
	     ->  '
	}
	a0.l     =  brace.level
	d0.w     =  (a0)+
	brace.level.l  =	a0
	a0.l     =  pop

30. Glance at stack for number to construct label for branch to 6 statement.

--Get break label
	push     =  a0
	a0.l     =  brace.level
	d0.w     =  (a0)
	bset     #15,D0
	a0.l     =  pop

31. Glance at stack for number to construct label after right brace
to serve as target for possible branch to 6 statement.

--Get last break label
	push     =  a0
	a0.l     =  brace.level
	d0.w     =  -2(a0)
	bset     #15,D0
	a0.l     =  pop

32. Generate label to replace a brace.  This is also used to construct
end of section labels and labels for data declarations.

Generate branch label
	movem.l  D1-D3/A0-A2,-(sp)
	a0.l     =  a1
	d3.w     =  d0
	(a0)+.b  =  '.'
	Binary to hex string	 7 33
	tst.b  bracket_flag
	!= + (a0).b  +=  32  ;
	movem.l  (sp)+,D1-D3/A0-A2
	d0       =  1 + 4
	l_length += d0
	tmp_ln   += d0


33. Convert number to 4 hex digits when generating unique labels.

Binary to hex string
	d0       =  0
	d0.w     =  D3
	a0.l    +=  4
	(a0).b   =  new_line
	a1       =  ^hextab
	d1       =  4 - 1
	{  d2.l	  =  d0
	   d2.l	 &=  15
	   -(a0).b  =  0(A1,D2)
	   d0.l	 >>= 4
	   dbra	  d1,}


34. This is for console messages. [used by 'print' macro]

Display string
	arg`a	  =  chandle
	clr.l    l_length
	l_length.b  =  (a0)+
	arg`b	  =  a0
	call     Write

35. As above, except output goes to output file.

Put line to output file
	arg`a	  =  ohandle
	clr.l    l_length
	l_length.b  =  (a0)+
	arg`b	  =  a0
	call     Write

36. AmigaDOS stuff.

--Initialize standard input and output
	a1    =  ^libname
	d0    =  0
	callex   OpenLibrary
	a6.l  =  d0
7 obtain file handles for output and input opened by CLI
	call     Output
	ohandle  =  d0
	chandle  =  d0
	call     Input
	ihandle  =  d0


37. Identify the name of a macro or procedure call which was
not found.  tmp_ln points to it.

--Tell the bad name
	l_length  =	0
	a0.l	=	tmp_ln
	{	l_length  +=  1
		(tmp_ln)+.b  ?  10
		bne	}
	arg`a	  =  chandle
	arg`b	  =  a0
	call     Write


38. Not really a procedure, of course.

Data sections

	section  three,bss

olen        ds.b  1
obuf        ds.b  ibufLen
ilen        ds.b  1
ibuf        ds.b  ibufLen
7 now on word boundary

infname     ds.b  30
outfname    ds.b  30

	   cnop	  0,2

( Stack to keep label numbers for right braces
  during input phase, and end of section labels
  during output phase. )
		  ds.w	maxbracenest
branch.stack   ds.w	4  7 room for stack to underflow a little
		  ds.w	maxbracenest
bracket.stack  ds.w	4  7 room for stack to underflow a little

( Table to keep track of definitions.  Each entry
  is a longword and a word.	The longword points to
  the name in the text stored in the filebuffer, and
  the word holds the type of the definition.  In the
  case of 'define' entries and data declarations, the
  type word is split into two bytes.  The low byte says
  it's a 'define', and the high byte is 0 for regular
  defines, but 1, 2, or 4 for 'byte', 'word', and 'long'
  declarations, respectively. )
sectlist	  ds.b	maxsects*6

( Buffer to hold text read in from source file. )
7 now using allocation
7filebuf	   ds.b  maxfsize


	section two,data

libname  dc.b  'dos.library',0

bufptr	  dc.l	ibuf
	cnop     0,2
brace.level	  dc.l	branch.stack
bracket.level  dc.l	bracket.stack
sect.name	  dc.l	sect.noname
sect.namelen   dc.b	16
sect.noname	  dc.b	'unnamed section',10
brace.prob	  dc.b	29,'unmatched braces in section: '

branch.table
	dc.b  '<=',177,'bgt'
	dc.b  '<=',0,'bhi'
	dc.b  '>=',177,'blt'
	dc.b  '>=',0,'bcs'
	dc.b  '~=',0,'beq'
	dc.b  '!=',0,'beq'
	dc.b  '->',0,'bra'
	dc.b  '<',177,0,'bge'
	dc.b  '<',0,0,'bcc'
	dc.b  '>',177,0,'ble'
	dc.b  '>',0,0,'bls'
	dc.b  '=',0,0,'bne'
	dc.b  '- ',0,'bpl'
	dc.b  '+',0,0,'bmi'
	dc.b  0

hextab   dc.b  '0123456789ABCDEF'

	      bstr  nogo,<couldn''t open file>
	      bstr  prob,<problem with output file>
	      bstr  what.mac,<didn''t find proc/macro...>
	      bstr  titl.bss,< section webroom,bss>
end.line	dc.b  1$-*-1
		dc.b  9,'end',10,10
1$
moveinst	dc.b  1$-*-1
		dc.b  9,'move.l',9
1$
moveminst	dc.b  1$-*-1
		dc.b  9,'movem.l',9
1$
rtsinst		dc.b	5,9,'rts',10
pushsuffix	dc.b	7,',-(sp)',10
popprefix	dc.b	6,'(sp)+,'
commachar	dc.b	1,','
newlinechar	dc.b	1,10

key.define  dc.b  'define ',0
key.byte    dc.b  'byte ',0
key.word    dc.b  'word ',0
key.long    dc.b  'long ',0

mnem.move   dc.b  'move',0
mnem.lea    dc.b  'lea',0
mnem.cmp    dc.b  'cmp',0
mnem.add    dc.b  'add',0
	    dc.b  'addq.l',0
mnem.sub    dc.b  'sub',0
	    dc.b  'subq.l',0
mnem.mulu   dc.b  'mulu',0
mnem.divu   dc.b  'divu',0
mnem.and    dc.b  'and',0
mnem.or     dc.b  'or',0
mnem.lsl    dc.b  'lsl',0
mnem.lsr    dc.b  'lsr',0

	section  one   7 to rationalize rts that web will put below here



38. Note that equ'd symbols must not start with a cap, lest the equ
statement be interpreted as a procedure section name.

--EQU statements
sysBase	  equ	    4
ibufLen	  equ	   100
maxfsize	  equ	80000
maxsects	  equ	  400
maxbracenest   equ	 50
( Character used for end-line comments. )
bullet.char	  equ	183
( Characters used to introduce comment sections. )
para.char	  equ	182
section.char   equ	167
( Alternate braces. )
leftg.char	  equ	171
rightg.char	  equ	187


39.

--Define macros for assembler

lref  macro
_LVO\1      equ  -6*(\2+4)
	   endm

call  macro
	   jsr   _LVO\1(A6)
	   endm

callex  macro
	   push  =  a6
	   a6.l  =  sysBase
	   jsr   _LVO\1(A6)
	   a6.l  =  pop
	   endm

print macro
	   a0  =	^\1
	   Display string 	    7 34
	   endm

fprint macro
	   a0  =	^\1
	   Put line to output file    7 35
	   endm

bstr  macro
\1    dc.b  1$-*-1
	   dc.b  '\2',10
1$
	   endm

is.it macro
	   chr  ? #\1
	   endm

40. The following way of getting values for the _LVO symbols to reference
library routines is not standard, but it avoids having to link with
amiga.lib (which is slow) or keeping the standard include files around
(which are bulky).

--Define library references

	lref     AllocMem,29
	lref     FreeMem,31
	lref     OpenLibrary,88

	lref     Output,6
	lref     Input,5
	lref     Write,4
	lref     Read,3
	lref     Open,1
	lref     Close,2
7	lref     IoErr,18  not used yet


SHAR_EOF
#	End of shell archive
exit 0