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