// MICRO Macros // last edited February 13, 1981 10:20 AM // Copyright Xerox Corporation 1979, 1981 get "micdecl.d" external // O.S. [ MoveBlock; SetBlock CleanupDiskStream // for trace listing ] // literals manifest [ argbl = 600 // argument buffer length ] // Static Storage static [ @argbuf // bottom of argument buffer @argend // end of argument buffer @argp // points to current bottom of arg buffer ] let argstr(nc) = valof // Allocate an n-char. argument string test (argp-nc-1 ls argbuf) ifso errx("Macro argument storage full") ifnot [ argp = argp-nc-1 @argp = nc+1 resultis argp+1 ] and colargs() = valof // Collect macro arguments, return # of args. // Note: the statement reading routine guarantees proper nesting // of parens and brackets, and nothing in the language can destroy it, // so no stack is necessary here. [ let stptr = sttop // Define first for assembly code let nest = 0 // Ditto let nargs = 0 let osptr = stptr [ static [ @achar ] // Process character // other characters goto achar // Stbuf!-1 contains endc, no need for end check let initmac() be // Initialize switch for colargs [ argbuf = alloctemp(argbl) argend = argbuf+argbl argp = argend let aswitch = alloctemp(#200) // no characters above #177 let arpb = table[ #11005 // ISZ nest,2 #20405 // achar: LDA 0 aswitch #15004 // achar1: DSZ stptr,2 #37004 // LDA 3 @stptr,2 #117000 // ADD 0 3 #3400 // JMP @0,3 0 // aswitch: #15004 // avalc: DSZ stptr,2 #772 // JMP achar1 ] achar = arpb+1 achar!5 = aswitch let avalc = arpb+7 SetBlock(aswitch, achar+1, #200) aswitch!$( = alpar aswitch!$) = arpb aswitch!$, = acomma aswitch!$[ = albr aswitch!$] = arpb aswitch!endc = aend aswitch!symc = avalc aswitch!numc = avalc aswitch!num6c = avalc ] aend: // ran off stbuf -- can't happen error("BRACKETS MISPAIRED -- BUG") alpar: // ( nest = nest-1 goto achar albr: // [ if nest ne 0 then [ nest = nest-1 goto achar ] @stptr = osptr-stptr nargs = nargs+1 break acomma: // , if nest ne 0 goto achar // enclosed in () or [] @stptr = osptr-stptr nargs = nargs+1 osptr = stptr goto achar ] repeat let nw = sttop-stptr sttop = stptr test argp-nw ls argbuf ifso [ errx("MACRO ARGUMENT STORAGE FULL") nargs = 0 ] ifnot [ argp = argp-nw MoveBlock(argp, stptr, nw) ] resultis nargs ] let mcall(ep, nargs) be // Do macro call [ if tracecalls then tracemcall(ep, nargs) let dp = nil // define first for assembly code let typ = ep!stype test typ gr maxtype ifso // Expand macro [ dp = fstop-(ep!mcsp) let free = tlbot-sttop-@dp test free le 0 ifso errx("STATEMENT TOO LONG") ifnot [ static [ @cleft; @cright; @cac1 ] let np, nl = nil, nil // argument pointer, length let param = nil // argument # let mask = nil // left/right mask goto cleft let initmac1() be [ let cswitch = alloctemp(#240) let cchar = table [ 11006b // cleft: ISZ dp,2 23006b // LDA 0 @dp,2 24415b // LDA 1 c177400 123700b // ANDS 1 0 34412b // LDA 3 cswitch 117000b // ADD 0 3 7400b // JSR @0,3 23006b // cright: LDA 0 @dp,2 24410b // LDA 1 c377 123400b // AND 1 0 34404b // LDA 3 cswitch 117000b // ADD 0 3 7400b // JSR @0,3 763b // JMP cleft 0 // cswitch: .-. 177400b // c177400: 177400 377b // c377: 377 0 // ccopy: STA 0 @sttop 0 // ISZ sttop 1400b // cskip: JMP 0,3 ] cleft = cchar cright = cchar+7 cchar!16b = cswitch cchar!21b = #42000 + lv sttop cchar!22b = #10000 + lv sttop SetBlock(cswitch, cchar+21b, #200) cswitch!Aend = actend cswitch!Aargn = actargn cswitch!Aarg2 = actarg2 cswitch!Aarg1 = actarg1 cswitch!Anargs = actnargs cswitch!Askip = cchar+23b cswitch!symc = actval cswitch!numc = actval cswitch!num6c = actval SetBlock(cswitch+200b, actlong, 40b) cac1 = table [ 121000b // MOV 1 0 1401b // JMP 1,3 ] ] actargn: // Copy param'th argument mask = not cac1() test mask ls 0 ifso [ dp = dp+1; param = (@dp)<>bytes^di = ac-$0 di = di-1 resultis Aargn ] ] if ac ne $0 then cklen = cklen-2 ] ifnot if ch ls 40b then // Packed value [ cp = cp-1 let val = @cp ap>>bytes^di = val<>bytes^di = val<>bytes^di = ch ] let nw = l - (di rshift 1) // space for packed body let dp = alloc(nw+1) MoveBlock(dp+1, endp-nw, nw) if (di & 1) ne 0 then dp>>bytes^2 = Askip // skip first byte (dp+nw)>>rh = Aend // mark end @dp = cklen resultis dp ]