1006 lines
21 KiB
PHP
1006 lines
21 KiB
PHP
|
; $$$$$$$$$$$$$$$$$$$ 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 s<e, c=*s, *s++=*e, *e--=c, endw
|
||
|
endf p
|
||
|
|
||
|
; text.begins a, b - a begins with b?
|
||
|
|
||
|
function text.begins, a, b
|
||
|
alias p=r0, q=r1, c=r2, d=r3
|
||
|
. p=a, q=b, d=c
|
||
|
while c=d, c=*p++, d=*q++
|
||
|
if c=0, break, end
|
||
|
if d=0, break, end
|
||
|
endw
|
||
|
if d<>0, 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
|