kolibrios-gitea/programs/games/codemaster/include/text.inc

1006 lines
21 KiB
PHP
Raw Normal View History

; $$$$$$$$$$$$$$$$$$$ 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