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