; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ ; *************** STAR^2 SOFTWARE **************** ; ???????????????????? TEXT ?????????????????????? ; fast portable text operations ; text.zero t ; initialize, *t=0 ; text.end t ; return end address (*t=0) ; text.n t ; get # characters ; text.copy a, b ; standard copy with 0 ; text.copy.n... ; copy with maximum size ; text.attach a, b ; attach b to a ; text.attach.c... ; attach c/haracter ; text.compare a, b ; compare lexical. <0> ; text.equal a, b ; equal? return 1/0 ; text.search a, b ; search for text. &/0 ; text.find a, c ; search for c. &/0 ; text.find.r a, c ; search for c in reverse ; text.count.c t, c ; count # of 'c's ; text.count.w t ; count # of words: 'a b c' ; text.count.n t ; count # of lines ; text.go t, n ; advance to line # ; text.upper t ; uppercase ; text.lower t ; lowercase ; text.reverse t ; reverse ; text.begins a, b ; begins with b? ; text.ends a, b ; ends with b? ; text.skip.0 t ; skip '0's. return & ; text.shift.l t, n ; shift characters left ; text.shift.la... ; shift left and assign ; text.expand t, n ; expand; shift right at 0 ; text.align t, n ; align; prefix with '0's ; x2t n, t ; convert number to text ; u2t n, t ; unsigned decimal ; h2t n, t ; hexadecimal ; b2t n, t ; binary ; t2x t ; convert text to number ; t2u t ; unsigned decimal ; t2h t ; hexadecimal ; t2b t ; binary ; print t, f, ... - a fast print formatted ; text to buffer macro debug { callf _say, bug.t, bug.t } RET equ ,0Dh,0Ah, ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; text.zero t - initialize macro text.zero t { . r0=t, *r0=0 } ; text.end t - return end address: *p=0 function text.end, t alias p=r0, c=r1 . p=t, c=1 while c, c=*p++, endw, p-- endf ; text.n t - get length, # characters function text.n, t alias p=r0, s=r1, c=r2 . p=t, s=p, c=1 while c, c=*p++, endw, p-s, p-- endf ; text.copy a, b - standard copy with ; 0 after. return advanced address function text.copy, a, b alias p=r0, s=r1, c=r2 . p=a, s=b, c=1 while c, c=*s++, *p++=c, endw, p-- endf ; text.copy.n a, b, n - copy with maximum ; size specified. return & function text.copy.n, a, b, n alias p=r0, s=r1, c=r2 . p=a, s=b loop n, c=*s++, *p++=c if c=0, break, end endl, p-- endf ; text.attach a, b - attach b to a. return & function text.attach, a, b text.end a text.copy r0, b endf ; text.attach.c t, c - attach c/haracter. ; return & function text.attach.c, t, c alias p=r0, x=r1 text.end t . x=c, *p++=x, *p=0 endf ; text.compare a, b - lexical comparison. ; return <0> function text.compare, a, b alias p=r0, s=r1, c=r2, d=r3 . p=a, s=b, c=d while c=d, c=*p++, d=*s++ if c=0, break, end if d=0, break, end endw, p=c, p-d endf ; text.equal a, b - equal? return 1/0 function text.equal, a, b text.compare a, b if false, return 1, end endf 0 ; text.find t, c - search for character: ; if t contains c. return &/0 function text.find, t, x alias p=r0, c=r1, k=r2 . p=t, k=x loop, c=*p if c=0, return 0, end if c=k, return p, end, p++ endl endf ; text.count.c t, c - count # of c/haracters function text.count.c, t, x locals n alias p=r0, c=r1, k=r2 . p=t, k=x, n=0, c=1 while c, c=*p++ if c=k, n++, end endw endf n ; text.count.w t - count # words 'a b c' function text.count.w, t try text.count.c t, ' ' . r0++ endf ; text.count.n t - count # lines function text.count.n, t try text.count.c t, 0Dh . r0++ endf ; text.go t, n - advance to line # function text.go, t, n loop n try t=text.find t, 0Dh . t+2 endl endf t ; text.upper t - convert to uppercase function text.upper, t alias p=r0, c=r1 . p=t loop, c=*p if c=0, return, end if c>=97 if c<=122, c-32, *p=c, end end, p++ endl endf ; text.lower t - convert to lowercase function text.lower, t alias p=r0, c=r1 . p=t loop, c=*p if c=0, return, end if c>=65 if c<=90, c+32, *p=c, end end, p++ endl endf ; text.reverse t - reverse text function text.reverse, t locals p alias s=r0, e=r1, c=r2 get p=text.end t . e=&(s-1), s=t while s0, return 0, end endf ; text.ends a, b - a ends with b? function text.ends, a, b locals p get p=text.end a text.n b . p-r0 text.equal p, b endf ; text.search t, c - search for text: ; if a contains b. return &/0 function text.search, a, b locals n, p get n=text.n a . p=a loop n text.begins p, b if true, return p, end . p++ endl endf 0 ; text.skip.0 a - skip 0s, return address or 0 function text.skip.0, a alias p=r0, c=r1 . p=a, c='0' while c='0', c=*p++, endw, p-- if c=0, return 0, end endf ; shift all characters left ; before: 'abc123' ; after <<3: '123' function text.shift.l, t, n alias p=r0, q=r1 . p=t, q=p, q+n text.copy p, q endf ; shift left and assign s to BITs ; copied out ('abc' in example above) function text.shift.la, t, s, n alias p=r0, q=r1 . p=t, q=p, q+n text.copy.n s, t, n text.shift.l t, n endf ; expand; shift all characters right. ; example: 'abc123' becomes 'XXXabc123' ; after expand 3 where X is unknown function text.expand, t, n locals x alias p=r0, q=r1, c=r2 get x=text.n t . p+t, p--, q=p, p+n, *p=0 loop x, *p--=*q--, endl endf ; prefix text with '0's or ensure maximum n. ; example: before: t='7FAB' ; text.align t, 8 ; after: t='00007FAB' function text.align, t, n locals tn alias n1=r0, n2=r1,\ c=r1, p=r2 get tn=text.n t . n2=n if n1=n2, return, end ; same size if n1>n2, p=t, *(p+n1)=0 ; exceeds maximum return ; end at t+n end, n-n1 ; else, n2>n1 text.expand t, n ; expand t . p=t, c='0' ; write '0's loop n, *p++=c, endl endf ; search text array ta for t using text.equal. ; return index or -1 (<0) if not found. ta is ; an array of text addresses (text[]) function text.array.equal, ta, t, n locals i alias p=r0, q=r1, x=r2 . i=0 loop n, x=i, q=ta, (u32) p=*(q+x*4) text.equal p, t if true, return i, end . i++ endl endf -1 ;;;;;;;;;;;;;;;;;; CONVERSIONS ;;;;;;;;;;;;;;;;;;; ; u2t n, t ; unsigned decimal ; h2t n, t ; hexadecimal ; b2t n, t ; binary ; convert unsigned 32BIT integer to text function u2t, n, t alias i=r0, x=r1, y=r2, c=r3, p=r7 push c p . i=n, p=t if i=0, *p++='0', *p=0 . r0=p go .r end . x=1999999Ah while i, c=i, mul x, i=y, y=&(y+y*4) . y+y, c-y, c+'0', *p++=c endw, *p=0 text.reverse t .r: pop p c endf ; convert 32BIT hexadecimal number to text function h2t, n, t alias p=r0, x=r1 . p=t if n=0, *p++='0', *p=0 return end while n, x=n, x&15 . x=*(@HEX+x), *p++=x, n>>>4 endw, *p=0 text.reverse t endf align @HEX: db '0123456789ABCDEF' ; convert 32BIT binary number to text function b2t, n, t alias p=r0, x=r1 . p=t if n=0, *p++='0', *p=0 return end while n, x=n, x&1, x+'0' . *p++=x, n>>>1 endw, *p=0 text.reverse t endf ; t2u t ; unsigned decimal ; t2h t ; hexadecimal ; t2b t ; binary ; convert text to unsigned 32BIT integer function t2u, t alias p=r0, c=r1, n=r2, x=r3 try text.skip.0 t . n=0 loop, c=*p++ if c=0, return n, end . x=n, x<<2, n+x, n+n, n-'0', n+c endl endf ; convert text to 32BIT hexadecimal function t2h, t alias p=r0, c=r1, n=r2 try text.skip.0 t . n=0 loop, c=*p++ if c=0, return n, end if c<=39h, c-30h else.if c>=61h, c-57h else, c-37h, end, n<<4, n+c endl endf ; convert text to 32BIT binary function t2b, t alias p=r0, c=r1, n=r2 try text.skip.0 t . n=0 loop, c=*p++ if c=0, return n, end . n<<1, n-'0', n+c endl endf ; convert number to text with alignment. ; example: n2t.a 1234h, t, 8, h ; after: t='00001234' macro n2t.a n, t, a, b { b#2t n, t text.align t, a } macro u2t.a n, t, a { n2t.a n, t, a, u } macro h2t.a n, t, a { n2t.a n, t, a, h } macro b2t.a n, t, a { n2t.a n, t, a, b } ;;;;;;;;;;;;;;;;;;;;; PRINT ;;;;;;;;;;;;;;;;;;;;;; ; print t, f, ... - a fast print formatted ; text to buffer ; %t %s - 'text'; "string" ; %c - character ; %n %u - 32BIT decimal unsigned ; %b - 32BIT binary ; %h - 32BIT hexadecimal ; %r - return. insert 0Dh, 0Ah ; %0 - 0/NULL ; %% - % macro print t, f, [p] { common callv !print, t, f, p } ; note: text.copy/reverse/etc and x2t ; must return end (*p=0) address for this ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; align integer BASE='n' ; !print(n, $t, $f, ...) !print: alias \ ; aliases... s=r6, p=r7,\ ; source, destiny c=r0, i=r1,\ va.s=r2,\ ; &va[...] start va.n=[esp+4],\ ; # va va=[r2+r1*4],\ ; current va[i] n=[.a], z=[.z] ; temporary . (u32) c=*(esp+8) ; text buffer . (u32) i=*(esp+12) ; format . va.s=&(esp+16) ; &va[...] start push s p . p=c, s=i, i=0 ; index=0 .get: . c=*s++ ; get c/haracter if c=0, go .e, end ; end? *s=0 if c<>'%' ; not % .1: . *p++=c ; copy c go .get ; next end . c=*s++ ; %x if c='%', go .1 ; 2 %% = % end if c='0', *p++=0 ; '0' = 0/NULL go .get end if c='r' ; 'r' = return . *p++=\ 0A0Dh, go .get end if c='c' ; %c . c=va, i++ ; get va[i++] . *p++=c go .get end if c='t' .t: ; %t %s - text . z=va, i++ ; get va[i++] pusha get z=\ text.copy p, z ; copy, save & popa . p=z ; advance text buffer go .get end if c='s', go .t end if c='n', go .n, end if c='u', go .n, end if c='h', go .n, end if c='b', go .n, end go .x ; unrecognized .n: . n=va, i++ ; get va[i] pusha ; copy/convert if c='n' ; number to text u2t n, p ; in selected base else.if c='u' u2t n, p else.if c='h' h2t n, p else.if c='b' b2t n, p end . z=r0 ; save end address popa . p=z ; advance text buffer go .get .x: . *p++='?' ; else, unrecognized, go .get ; replace with '?' .0: . r0=0, go .q ; error .e: . r0=p, *r0=0 ; success. terminate .q: ; return end pop p s ret ; callv adjusts esp after endal ; end alias .a dd 0 .z dd 0 ;;;;;;;;;;;;;;; CHARACTER TABLES ;;;;;;;;;;;;;;;;; ; ILT - insensitive lookup table. A-Z/a-z are ; the same. this increases processing speed by ; many times. example: if (tt[a]=tt[b]) instead ; of: if ((a>='a'&a<='z')&(b>='a'&b<='z')) | ; ((a>='A'&a<='Z')&(b>='Z'&b<='Z')) ; TLT - type lookup table. each byte contains ; C.X BITs to determine its type fast in one ; comparison. example: if tt[c]&SYMBOL align 8 ; byte XLT[128]= ILT db \ 00h,01h,02h,03h,04h,05h,06h,07h,08h,09h,0Ah,0Bh,0Ch,0Dh,0Eh,0Fh,\ 10h,11h,12h,13h,14h,15h,16h,17h,18h,19h,1Ah,1Bh,1Ch,1Dh,1Eh,1Fh,\ 20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Ah,2Bh,2Ch,2Dh,2Eh,2Fh,\ 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h,3Ah,3Bh,3Ch,3Dh,3Eh,3Fh,\ 40h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh,\ 50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,5Bh,5Ch,5Dh,5Eh,5Fh,\ 60h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh,\ 50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,7Bh,7Ch,7Dh,7Eh,7Fh TLT db \ 00h,80h,80h,80h,80h,80h,80h,80h,80h,80h,40h,80h,80h,40h,80h,80h,\ 80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,\ 20h,10h,04h,04h,10h,04h,04h,04h,04h,04h,04h,04h,04h,04h,10h,04h,\ 01h,01h,01h,01h,01h,01h,01h,01h,01h,01h,04h,04h,04h,04h,04h,10h,\ 10h,0Ah,0Ah,0Ah,0Ah,0Ah,0Ah,02h,0Ah,02h,02h,0Ah,02h,0Ah,02h,02h,\ 02h,02h,02h,02h,02h,02h,02h,02h,02h,02h,02h,04h,04h,04h,04h,10h,\ 04h,0Ah,0Ah,0Ah,0Ah,0Ah,0Ah,02h,0Ah,02h,02h,0Ah,02h,0Ah,02h,02h,\ 02h,02h,02h,02h,02h,02h,02h,02h,02h,02h,02h,04h,04h,04h,04h,80h ; 76543210b C.NULL = 00000000b ; 0 C.NUMBER = 00000001b ; 0-9 C.ALPHA = 00000010b ; A-Z, a-z C.SYMBOL = 00000100b ; all symbols except _.?!@$ C.NUMERIC = 00001000b ; A-F/a-f, h,b,k,m/H,B,K,M C.SYMBOLIC = 00010000b ; _.?!@$ C.SPACE = 00100000b ; ' ', '/t' C.RETURN = 01000000b ; 0Dh, 0Ah C.IGNORE = 10000000b ; extended: 1.XXXXXXXb C.KEYWORD = 11111111b C.DIGIT = C.NUMBER or C.NUMERIC C.NAME = C.ALPHA or C.NUMBER or C.SYMBOLIC C.SYMBOLS = C.SYMBOL or C.SYMBOLIC C.ALPHAN = C.ALPHA or C.NUMBER C.VISIBLE = C.ALPHAN or C.SYMBOLS C.WHITE = C.SPACE or C.RETURN C.BLANK = C.WHITE or C.IGNORE C.END = C.SYMBOL or C.WHITE C.0 = 0 function is.c, c, type . r0=c, r0=*(TLT+r0), r0&type endf macro if.is c, t { is.c c, t if true } ;;;;;;;;;;;;;;;;;;; PARSE TEXT ;;;;;;;;;;;;;;;;;;; ; skip while type and not 0 ; get p=text.skip.while p, C.WHITE function text.skip.while, t, type alias p=r0, q=r1, c=r2 . p=t, c=1 while c, c=*p++ . c=*(TLT+c), c&type endw, p-- endf ; skip until type and while not 0. ; kind of tricky ; get p=text.skip.until p, C.RETURN function text.skip.until, t, type alias p=r0, q=r1, c=r2 . p=t, c=0 while c=0, c=*p++ if c=0, return 0, end . c=*(TLT+c), c&type endw, p-- endf ; copy while type and not 0 ; get s=text.copy.while t, s, C.NAME function text.copy.while, t, s, type alias a=r7, b=r6, c=r1, x=r2 . a=t, b=s, c=*b if c=0, return 0, end while c, c=*b++, *a++=c . x=*(TLT+c), x&type if x=0, break, end endw, a--, *a=0, b-- endf b ; copy until type and while not 0 ; get s=text.copy.until t, s, C.END function text.copy.until, t, s, type alias a=r7, b=r6, c=r1, x=r2 . a=t, b=s, c=*b if c=0, return 0, end while c, c=*b++, *a++=c . x=*(TLT+c), x&type if x, break, end endw, a--, *a=0, b-- endf b ; copy until 'c'/x. if 0 or return is ; encountered before, return 0 function text.copy.until.c, t, s, x alias a=r7, b=r6, c=r1 . a=t, b=s, c=*b if c=0, return 0, end while c, c=*b++, *a++=c if c=x, break, end if c=0, return 0, end if c=0Dh, return 0, end endw, a--, *a=0, b-- endf b ; skip whitespace and returns ; (if parse.skip.r?) or only spaces ; and tabs. return advanced & align boolean parse.skip.r?=YES function text.skip.ws, t if parse.skip.r? text.skip.while t, C.WHITE else text.skip.while t, C.SPACE end endf ; skip all whitespace, returns ; (if parse.skip.r?) and comments. ; return advanced & function text.skip.x, t locals q alias p=r0, c=r1 . p=t, q=p .get: . p=q, c=*p if c=0 return 0 end if.is c, C.WHITE try q=text.skip.ws q end . p=q, c=*p if c=';' try q=text.skip.until \ q, C.RETURN . p+2 go .get end endf q function text.get, a, b locals q alias p=r0, c=r1 . q=b try q=text.skip.x q . c=*p if c=0, return 0, end if.is c, C.SYMBOL . p=a, *p++=c, *p=0, q++ return q end text.copy.until a, q, C.END endf ;;;;;;;;;;;;;;;; SOURCE, DESTINY ;;;;;;;;;;;;;;;;; align void source.p, destiny.p, token.p integer source.n, destiny.n, token.n macro set.source p { . source.p=p } macro set.destiny p { . destiny.p=p } macro set.token p { . token.p=p } function skip.while, type get source.p=text.skip.while \ source.p, type endf function skip.until, type get source.p=text.skip.until \ source.p, type endf function copy.while, type get source.p=text.copy.while \ token.p, source.p, type endf function copy.until, type get source.p=text.copy.until \ token.p, source.p, type endf function copy.until.c, c get source.p=text.copy.until.c \ token.p, source.p, c endf macro skip.space { skip.while C.SPACE } macro skip.white { skip.while C.WHITE } macro skip.line { skip.until C.RETURN } ; skip all whitespace, returns ; (if parse.skip.r?) and comments. ; return advanced & function skip.x alias p=r0, c=r1 .get: . p=source.p, c=*p if c=0, return 0, end if.is c, C.WHITE try skip.while C.WHITE end . p=source.p, c=*p if c=';' try skip.until C.RETURN . source.p+2 go .get end . p=source.p endf p ; get token function get.token alias p=r0, c=r1 try skip.x . c=*p if c=0, return 0, end if.is c, C.SYMBOL . p=token.p, *p++=c, *p++=0 . source.p++, p=source.p if c='''', c=*p if c='''', source.p++ return source.p end try copy.until.c '''' . source.p++ end . p=source.p return end copy.until C.END endf ; MOVE TO PARSE.INC... ;;;;;;;;;;;;;;;;;;; NAME TABLE ;;;;;;;;;;;;;;;;;;; ; name table: ; 'ann',0, 'kim',0, 'sue',0 align 4 void name.table, name.table.p,\ name.table.n, name.table.size, name.table.end ; allocate name.table function create.name.table, size try name.table=call !allocate, size . name.table.p=r0, r0+size . name.table.end=r0, name.table.n=0 . name.table.size=0 endf 1 ; get name address by index function get.name, i locals p . p=name.table loop i get p=text.end p . p++ endl endf p ; search for name. return index or -1 function search.name, t locals i, p . p=name.table, i=name.table.n loop i get.name i text.equal p, r0 if true, return i, end endl endf -1 ; attach 'text'. return address function create.name, t locals p, n . p=name.table.p text.n t . r0++, n=r0, r0+p if r0>=name.table.end return 0 end text.copy name.table.p, t . r0=p, r0+n, name.table.p=r0 . name.table.n++, r0=n . name.table.size+r0 endf p ; remove name at index function remove.name, i locals p, q, n, size get p=get.name i get n=text.n p . i++ get q=get.name i . r0=name.table.p, r0+name.table.size . r0-p, size=r0, r0=n . name.table.size-r0, name.table.p-r0 memory.copy p, q, size . name.table.n-- endf ; get name at index function copy.name, i, t get.name i text.copy t, r0 endf ; name structure: 16 bytes virtual at 0 ?define: .type dd 0 ; type: TTTT... .value dd 0 ; name index .name dd 0 ; value or index .i dd 0 ; anything, align 16 .$=$ END virtual powers DEFINE.*, ALIVE, USED,\ D, ABLE, NUMERIC ; .type = ; TTTT.SSSS XXXXXXXX XXXXXXXX XXX.NR.DUA ; 23-16 15-8 7-0 ; T: type: number, define, constant, label, ; macro, register, instruction, variable ; S: data size ; P: parameter 1 ; Q: parameter 2 ; X: anything ; N: 1=numeric, 0=symbolic ; R: 1=redefinable, 0=not ; D: 1=defined, 0=not ; U: 1=used, 0=not ; A: 1=alive, 0=dead ; name structures. last structure is ; defines.p+((defines.n-1)*48) align 4 void defines.p ; name structures void defines.end.p ; end allocation integer defines.n ;;;;;;;;;;;;;;;;;;;;; ERRORS ;;;;;;;;;;;;;;;;;;;;; ; MOVE TO ASSEMBLER.INC text errors.ta[]=\ E.NONE ='None',\ E.SYNTAX ='Syntax',\ E.LOAD ='Error loading',\ E.FILE ='File I/O error',\ E.UNEXPECT ='Unexpected',\ E.CPU ='Unsupported by CPU',\ E.ADDRESS ='Address not aligned',\ E.OPERANDS ='Invalid operand/s',\ E.AMODE ='Invalid addressing mode',\ E.SHIFT ='Invalid shift #',\ E.NUMBER ='Invalid number',\ E.NUMBER2 ='Number can''t be encoded',\ E.VALUE ='Value exceeds size',\ E.ALIGN ='Number must be aligned',\ E.POWER ='# must be power of 2',\ E.REGISTER ='Register expected',\ E.EXPECTN ='Number expected',\ E.EXPECTA ='Name expected',\ E.INAME ='Invalid name',\ E.NAME ='Name too long',\ E.RESERVE ='Reserved name',\ E.UNDEFINE ='Undefined',\ E.REDEFINE ='Redefinition',\ E.EXPECTT ='Text expected',\ E.ENDT ='Text has no end ''',\ E.COMMA =', expected',\ E.END ='end expected',\ E.MISMATCH ='Mismatched parenthesis' ;;;;;;;;;;;;;;;;;;; KEYWORDS ;;;;;;;;;;;;;;;;;;;;; ; MOVE TO ASSEMBLER.INC text keywords.ta[]=\ K.ALIGN='align', K.BYTE='byte',\ K.D1='d1', K.D2='d2', K.D4='d4', K.D8='d8',\ K.DEFINE='define', K.DOUBLE='double',\ K.EQUATE='equate', K.FLOAT='float',\ K.FORMAT='format', K.INCLUDE='include',\ K.INJECT='inject', K.INTEGER='integer',\ K.MAIN='main', K.ORG='org',\ K.RESTORE='restore', K.TEXT='text',\ K.USE='use', K.VOID='void' align 4 void keywords.ta.p=keywords.ta integer keywords.n=keywords.ta.$ function is.keyword, t if keywords.n=0, return -1, end text.array.equal \ keywords.ta.p, t, keywords.n endf