flat assembler
Message board for the users of flat assembler.

Index > Non-x86 architectures > [ARM] Reusable Binary Modules: Import+Export Library

Author
Thread Post new topic Reply to topic
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 09 Apr 2014, 14:51
Examples of how to export functions to a library (.L) then import them from another module. Easy import+export by name using load and store directives. Create it once then forget about it. Reuse it millions of times.

In version=0: ARM mode. Fast-call a1-a4+v1-v4. 8 parameters maximum. Modular functions, "position independent" with no global references except to functions that are imported in the same order. Any "static" data or literal tables (text and big numbers) must be incorporated inside of the functions and use PC-relative loads. Absolute memory addresses are allowed (example: RAM, VGA, timer, devices).

See ZIP Attachment 4 Updated Magic-ARM Library, Examples, Tests, Disassembler. Scroll down

EXAMPLE LIBRARY: STRING.ASM > STRING.*L
Code:
; EXPORT FUNCTIONS TO STRING.L

include 'library.inc'

export strlen, strcpy, strcmp, strequ

; strlen(s) - get string length, # characters

function strlen, s
  alias s=a1, b=a2, c=v1
  . c=1, b=s
  .while c           ; until 0
    . (u8) c=*s++    ; read c
  .endw
  . s--, s-b         ; return current-start
endf

; strcpy(a, b) - standard copy with 0 after

function strcpy, a, b
  alias a=a1, b=a2, c=v1
  . c=1
  .while c
    . (u8) c=*b++    ; read
    . (u8) *a++=c    ; copy
  .endw
  . a--              ; return end
endf

; strcmp(a, b) - lexical comparison.
; return <0>

function strcmp, a, b
  alias a=a1, b=a2,\
   c=v1, d=v2
   . c=1, d=c
  .while c=d         ; while equal
    . (u8) c=*a++
    . (u8) d=*b++
    .if c=0          ; and both nonzero
      .break
    .end
    .if d=0
      .break
    .end
  .endw
  . a=c-d            ; return *a-*b
endf

; strequ(a, b) - equal? return 1/0

function strequ, a, b
  strcmp
  .if false
    return 1
  .end
endf 0    
TEST EXAMPLE.ASM > EXAMPLE.*BIN
Code:
; EXAMPLE. IMPORT FUNCTIONS FROM STRING.L

include 'z.inc'

import string,\
 strlen, strcpy, strcmp, strequ

; example code...

nop
strcpy 1, 2
strcmp 1, 2    
DISASSEMBLY OF STRING+DRAW

Syntaxes generate highly optimized ARM assembler:
Code:
00000000 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000004 E3A04001 mov    v1, 1
00000008 E1A01000 mov    a2, a1
0000000C E3540000 cmp    v1, 0
00000010 0A000001 beq    1Ch
00000014 E4D04001 ldrb   v1, [a1], 1
00000018 EAFFFFFB b      0Ch
0000001C E2500001 subs   a1, a1, 1
00000020 E0500001 subs   a1, a1, a2
00000024 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000028 E92D5FF0 stmdb  sp!, {v1-ip,lr}
0000002C E3A04001 mov    v1, 1
00000030 E3540000 cmp    v1, 0
00000034 0A000002 beq    44h
00000038 E4D14001 ldrb   v1, [a2], 1
0000003C E4C04001 strb   v1, [a1], 1
00000040 EAFFFFFA b      30h
00000044 E2500001 subs   a1, a1, 1
00000048 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
0000004C E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000050 E3A04001 mov    v1, 1
00000054 E1A05004 mov    v2, v1
00000058 E1540005 cmp    v1, v2
0000005C 1A000008 bne    84h
00000060 E4D04001 ldrb   v1, [a1], 1
00000064 E4D15001 ldrb   v2, [a2], 1
00000068 E3540000 cmp    v1, 0
0000006C 1A000000 bne    74h
00000070 EA000003 b      84h
00000074 E3550000 cmp    v2, 0
00000078 1A000000 bne    80h
0000007C EA000000 b      84h
00000080 EAFFFFF4 b      58h
00000084 E0540005 subs   a1, v1, v2
00000088 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
0000008C E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000090 EBFFFFED bl     4Ch
00000094 E3500000 cmp    a1, 0
00000098 1A000001 bne    0A4h
0000009C E3A00001 mov    a1, 1
000000A0 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
000000A4 E3A00000 mov    a1, 0
000000A8 E8BD9FF0 ldmia  sp!, {v1-ip,pc}

; Disassembly of DRAW.L:

00000000 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000004 E3A02000 mov    a3, 0
00000008 E3822C05 orr    a3, a3, 500h
0000000C E0130291 muls   a4, a2, a3
00000010 E0933080 adds   a4, a4, a1, lsl 1
00000014 E3A01000 mov    a2, 0
00000018 E3811602 orr    a2, a2, 200000h
0000001C E0910003 adds   a1, a2, a4
00000020 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000024 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000028 E3A02000 mov    a3, 0
0000002C E3822602 orr    a3, a3, 200000h
00000030 E3A01000 mov    a2, 0
00000034 E3811A0B orr    a2, a2, 0B000h
00000038 E3811701 orr    a2, a2, 40000h
0000003C E3510000 cmp    a2, 0
00000040 0A000002 beq    50h
00000044 E0C200B2 strh   a1, [a3], 2
00000048 E2511001 subs   a2, a2, 1
0000004C EAFFFFFA b      3Ch
00000050 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000054 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000058 E1A04002 mov    v1, a3
0000005C E92D000F stmdb  sp!, {a1-a4}
00000060 E3A02000 mov    a3, 0
00000064 E3822C05 orr    a3, a3, 500h
00000068 E0130291 muls   a4, a2, a3
0000006C E0933080 adds   a4, a4, a1, lsl 1
00000070 E3A01000 mov    a2, 0
00000074 E3811602 orr    a2, a2, 200000h
00000078 E0910003 adds   a1, a2, a4
0000007C E1A0A000 mov    v7, a1
00000080 E8BD000F ldmia  sp!, {a1-a4}
00000084 E1A0000A mov    a1, v7
00000088 E1C040B0 strh   v1, [a1]
0000008C E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000090 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000094 E1A04003 mov    v1, a4
00000098 E1A05002 mov    v2, a3
0000009C E92D000F stmdb  sp!, {a1-a4}
000000A0 E3A02000 mov    a3, 0
000000A4 E3822C05 orr    a3, a3, 500h
000000A8 E0130291 muls   a4, a2, a3
000000AC E0933080 adds   a4, a4, a1, lsl 1
000000B0 E3A01000 mov    a2, 0
000000B4 E3811602 orr    a2, a2, 200000h
000000B8 E0910003 adds   a1, a2, a4
000000BC E1A0A000 mov    v7, a1
000000C0 E8BD000F ldmia  sp!, {a1-a4}
000000C4 E1A0000A mov    a1, v7
000000C8 E3550000 cmp    v2, 0
000000CC 0A000002 beq    0DCh
000000D0 E0C040B2 strh   v1, [a1], 2
000000D4 E2555001 subs   v2, v2, 1
000000D8 EAFFFFFA b      0C8h
000000DC E8BD9FF0 ldmia  sp!, {v1-ip,pc}
000000E0 E92D5FF0 stmdb  sp!, {v1-ip,lr}
000000E4 E1A04003 mov    v1, a4
000000E8 E1A05002 mov    v2, a3
000000EC E92D000F stmdb  sp!, {a1-a4}
000000F0 E3A02000 mov    a3, 0
000000F4 E3822C05 orr    a3, a3, 500h
000000F8 E0130291 muls   a4, a2, a3
000000FC E0933080 adds   a4, a4, a1, lsl 1
00000100 E3A01000 mov    a2, 0
00000104 E3811602 orr    a2, a2, 200000h
00000108 E0910003 adds   a1, a2, a4
0000010C E1A0A000 mov    v7, a1
00000110 E8BD000F ldmia  sp!, {a1-a4}
00000114 E1A0000A mov    a1, v7
00000118 E3550000 cmp    v2, 0
0000011C 0A000003 beq    130h
00000120 E0D4C0B2 ldrh   ip, [v1], 2
00000124 E0C0C0B2 strh   ip, [a1], 2
00000128 E2555001 subs   v2, v2, 1
0000012C EAFFFFF9 b      118h
00000130 E8BD9FF0 ldmia  sp!, {v1-ip,pc}    
IMPORT/EXPORT MACROS (IMPORT.INC)
Code:
;;;;;;;;;;;;;;;;;;; IMPORT.INC ;;;;;;;;;;;;;;;;;;;

; write library (.L) file containing
; functions. example:

; export strlen, strcpy, strcmp, strequ

macro export [f] {
 common
  local n, ..f
  n=0
 forward
  n=n+1
 common         ; 16 byte header:
  db 'L', 0     ; signature, version=0
  dh n          ; # functions (offset=Ah)
  dw ..f        ; functions begin
  dw 0, 0       ; reserved
 forward        ; array of:
  local l
  l db `f, 0    ; function name
  times \       ; align 24
   24-($-l) \
   db 0
  dw !#f        ; function offset
  dw !#f#.$     ; function size
 common
  while $ mod 4 ; align 4 for ARM
   db 0         ; (it should already
  end while     ; be aligned)
  ..f:          ; functions begin
}     

; load s/pecific functions from library*.L
; into current module. example:

; import string,\
; strlen, strcpy, strcmp, strequ

macro import l, [f] {
 common
  local a, b, c,\
   p, i, n, s, o,\
   fb, found, equal
  virtual at 0            ; virtual file
   p:: file `l#'.L'
  end virtual
  load a byte from p:0    ; signature
  if a<>'L'
   'Invalid signature'
  end if
  load a byte from p:1    ; version
  if a<>0
   'Version must be 0'
  end if
  load n hword \          ; # functions total
   from p:2
  load fb word \          ; functions begin
   from p:4
 forward                  ; iterate through
  local fs                ; function names...
  virtual at 0
   fs::                   ; current function
   i=$                    ; structure:
   db `f, 0               ; name
   times \                ; align 24
    24-($-i) db 0
   dw 0, 0                ; offset, size
  end virtual
  i=0
  repeat n                ; search functions
   equal=1                ; for name...
   found=0
   repeat 6-1             ; read and compare
    load a word from p:\  ; names. 24 bytes,
     16+(i*32)+((%-1)*4)  ; 4 a time
    load b word from \
     fs:((%-1)*4)
    if a<>b               ; while equal
     equal=0
     break
    end if
   end repeat
   if equal
    found=16+(i*32)       ; offset
    break
   end if
   i=i+1
  end repeat
  if found=0
   'Name not found:' f
  end if
  load o word from \      ; read offset
   p:found+24
  load s word from \      ; and size
   p:found+28
  store word o at fs:24   ; store in current
  store word s at fs:28   ; function structure
  !#f:                    ; !name:
  repeat s/4              ; extract found
   load a word from \     ; function from file
    p:o+((%-1)*4)         ; 4 bytes at a time
   dw a                   ; insert <here>
  end repeat
  macro f [ps] \{         ; fast-call macro
   macro list.e a, [p] \  ; store register
    \\{ \forward \        ; names in list
     a equ p \\}
   list.e ?rs,\
    v4,v3,v2,v1,\
    a4,a3,a2,a1
   \forward
     match x, ?rs         ; restore register
      \\{ restore ?rs     ; names
      let x=ps \\}        ; send parameter
   \common
     bl !\#f
  \}
 common
  ; ...
}    


Description:
Filesize: 69.21 KB
Viewed: 7684 Time(s)

library.gif


Description:
Download
Filename: arm_library.zip
Filesize: 124.98 KB
Downloaded: 1056 Time(s)



Last edited by m3ntal on 09 Apr 2014, 17:04; edited 1 time in total
Post 09 Apr 2014, 14:51
View user's profile Send private message Reply with quote
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 09 Apr 2014, 15:56
Magic-ARM Updates (See Attachment: ARM_LIBRARY.ZIP):

* New TEXT.INC functions: t2i/u/h/b, expand, prefix, enclose, align, skip/copy while/until, array equal/begins
* SYSTEM.INC: Basic memory organization. Increased memory. 8 megabytes by default. @available displays how much memory is remaining at compile-time (Ctrl+F9)
* ARM.INC: Replaced old movi which had a glitch. Now contains 3 movi variations: mov+orr and/or rotate* and movw/t (* not needed in FASMARM, standard mov does this)
* FILE.INC: open/create is binary mode (was "text mode" = automatic translations of return characters)

Tip: To enable ARM Cortex A9 in QEMU for VFP, movw/t, division and Angel ARM semi-hosting, try something like this (where %name%=NAME.BIN):
Code:
qemu-system-arm -cpu cortex-a9 -m 16m -semihosting -kernel %name%    
TEXT.INC
Code:
; $$$$$$$$$$$$$$$$$$ MAGIC-ARM $$$$$$$$$$$$$$$$$$$
; *************** STAR^2 SOFTWARE ****************
; ?????????????????? TEXT.INC ????????????????????

; fast portable ARM text operations

; text.n t          ; get # characters (size-1)
; text.write a, b   ; copy with no 0 after
; text.copy a, b    ; standard copy with 0 after
; text.copy.n ...   ; copy with maximum size
; text.attach a, b  ; attach b to a; "concencate"
; text.attach.c...  ; attach character
; text.compare a, b ; compare. return <0>
; text.find t, c    ; search for c. return &/0
; text.find.last... ; search for c reverse
; text.count.c t, c ; count occurrances of c
; text.count.n t    ; count # lines
; text.begins a, b  ; begins with b?
; text.ends a, b    ; ends with b?
; text.upper t      ; convert to uppercase
; text.lower t      ; convert to lowercase
; text.reverse t    ; reverse
; text.expand t, n  ; shift right
; text.prefix a, b  ; prepend
; text.enclose.c... ; enclose in 'c'
; text.align t...   ; align to size: '007F'

; text.array.equal ta, t, n
; text.array.begins ta, t, n

; text.skip.while t, type
; text.skip.until t, type
; text.copy.while a, b, type
; text.copy.until a, b, type

; set.source r
; set.token r
; set.stream s, t

; skip.while type
; skip.until type
; copy.while type
; copy.until type

; skip.space
; skip.white
; skip.comment
; skip.all

; i2t n, t         ; number/text conversions
; u2t n, t
; h2t n, t
; b2t n, t

; t2i t
; t2u t
; t2h t
; t2b t

;;;;;;;;;;;;;;; CHARACTER TABLES ;;;;;;;;;;;;;;;;;

; ILT - insensitive lookup table. A-Z/a-z are
; the same. 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: if tt[c]&SYMBOL

macro define.xlt {

align 4

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
}

define.xlt

;            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

; is c of type? a1=c, a2=type

function is.c, c, type
  . a1&0FFh, a3=TLT, a3+a1
  . (u8) a1=*a3, a1&a2
endf

macro is.c c, t {
  . a1=c, a2=t
  is.c
}

macro if.is c, t {
  is.c c, C.#t
  .if true
}

numeric ZERO.C='0', SPACE.C=' ',\
 COMMA.C=',', COLIN.C=':', SEMI.C=';',\
 POUND.C='#', ASSIGN.C='=', SLASHB.C='\'

NL equ ,0Dh,0Dh,

macro .if.text.equal a, b
 { !if text.equal, a, b }
macro .if.not.text.equal a, b
 { !if.n text.equal, a, b }
macro .if.text.find a, b
 { !if text.find, a, b }
macro .if.text.find.last a, b
 { !if text.find.last, a, b }
macro .if.text.begins a, b
 { !if text.begins, a, b }
macro .if.text.ends a, b
 { !if text.ends, a, b }

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; text.end(t) - advance a1 to end (*t=0)

function text.end, t
  alias t=a1, c=v1
  . c=1
  .while c           ; until 0
    . (u8) c=*t++    ; read c
  .endw
  . t--
endf

; text.n(t) - get text length, # characters

function text.n, t
  alias t=a1, b=a2, c=v1
  . c=1, b=t
  .while c           ; until 0
    . (u8) c=*t++    ; read c
  .endw
  . t--, t-b         ; return current-start
endf

; text.write(a, b) - copy with no 0 after

function text.write, a, b
  alias a=a1, b=a2, c=v1
  .forever
    . (u8) c=*b++    ; read
    .if c=0
      return
    .end
    . (u8) *a++=c    ; copy
  .endfv
endf

; text.copy(a, b) - standard copy with 0 after

function text.copy, a, b
  alias a=a1, b=a2, c=v1
  . c=1
  .while c
    . (u8) c=*b++    ; read
    . (u8) *a++=c    ; copy
  .endw
  . a--              ; return end
endf

; text.copy.n(a, b, n) - copy with maximum
; size specified

function text.copy.n, a, b, n
  alias a=a1, b=a2,\
   n=a3, c=v1
  .repeat n          ; # times
    . (u8) c=*b++    ; read
    . (u8) *a++=c    ; copy
    .if c=0          ; end?
      .break
    .end
  .endr
  . a--
endf

; text.attach(a, b) - attach b to a

function text.attach, a, b
  alias a=a1,\
   b=a2, p=v1
  . p=b
  text.end
  . b=p
  text.copy
endf

; text.attach.c(t, c) - attach c to t

function text.attach.c, t, c
  alias t=a1, c=v2
  . c=a2
  text.end
  . (u8) *t++=c, (u8) *t=0
endf

; text.compare(a, b) - lexical comparison.
; return <0>

function text.compare, a, b
  alias a=a1, b=a2,\
   c=v1, d=v2
   . c=1, d=c
  .while c=d         ; while equal
    . (u8) c=*a++
    . (u8) d=*b++
    .if c=0          ; and both nonzero
      .break
    .end
    .if d=0
      .break
    .end
  .endw
  . a=c-d            ; return *a-*b
endf

; text.equal(a, b) - equal? return 1/0

function text.equal, a, b
  text.compare
  .if false
    return 1
  .end
endf 0

; text.find(t, c) - search for character.
; return address or 0

function text.find, t, c
  alias t=a1,\
   c=v1, key=a2
  .forever           ; loop
    . (u8) c=*t      ; read c
    .if c=0          ; end?
      return 0       ; not found
    .end
    .if c=key        ; found?
      return t       ; t=address
    .end
    . t++            ; next
  .endfv
endf

; text.find.last(t, c) - search for c reverse

function text.find.last, t, c
  alias t=a1, c=a2,\
   key=v1, p=v2
  . key=c, p=t       ; save begin
  . c=1
  .while c           ; advance to end-1,
    . (u8) c=*t++    ; last character
  .endw
  . t-2
  .while t>p         ; loop backwards
    . (u8) c=*t      ; until beginning
    .if c=key        ; found
      return t       ; t=address
    .end
    . t--            ; previous
  .endw
endf 0               ; not found

; text.count.c(t, c) - count # of
; characters in text

function text.count.c, t, c
  alias p=v1, c=v2, n=v3
  . p=a1, c=a2, n=0
  .while true
    get p=text.find p, c
    .if true
      . p++, n++
    .end
  .endw
endf n

; text.count.n(t) - count # lines

function text.count.n, t
  text.count.c a1, 0Dh
  .if a1>0
    . a1++
  .end
endf

; text.begins(a, b) - a begins with b?

function text.begins, a, b
  alias a=a1, b=a2,\
   c=v1, d=v2, e=v3
  . c=1, d=c
  .while c=d         ; while equal
    . (u8) c=*a++    ; load *a/*b
    . (u8) d=*b++
    . e=c|d          ; and both nonzero
    .breakz          ; break if either=0
  .endw
  .if d<>0           ; *b must=0
    return 0
  .end
endf

; text.ends(a, b) - a ends with b?

function text.ends, a, b
  alias \
   a=v1, b=v2, p=v3
  . a=a1, b=a2
  text.end            ; a=end(a)-length(b)
  . p=a1, a1=b
  text.n
  . p-a1, a1=p, a2=b
  text.compare
  .if false
    return 1
  .end
endf 0

; text.upper(t) - convert to uppercase

function text.upper, t
  alias t=a1, c=v1
  .forever
    . (u8) c=*t      ; get c
    .if c=0          ; end?
      return t
    .end
    .if c>=97        ; lowercase?
      .if c<=122
        . c-32
        . (u8) *t=c  ; copy c
      .end
    .end
    . t++            ; next c
  .endfv
endf

; text.lower(t) - convert to lowercase

function text.lower, t
  alias t=a1, c=v1
  .forever
    . (u8) c=*t      ; get c
    .if c=0          ; end?
      return
    .end
    .if c>=65        ; uppercase?
      .if c<=90
        . c+32
        . (u8) *t=c  ; copy c
      .end
    .end
    . t++            ; next c
  .endfv
endf

; text.reverse(t) - reverse text

function text.reverse, t
  alias t=a1,\
   p=a2, s=a3,\
   c=v1, d=v2
  . s=t, c=1         ; save start
  .while c
    . (u8) c=*t++    ; advance to end
  .endw
  . p=t-2, t=s
  .while t<p         ; exchange *t++/*p--
    . (u8) c=*t
    . (u8) d=*p
    . (u8) *t++=d
    . (u8) *p=c
    . p--
  .endw
  . t--
endf

; expand; shift all characters right.
; example: 'abc123' becomes 'XXXabc123'
; after expand 3 where X is unknown

function text.expand, t, n
  alias t=v1, p=v2,\
   n=v3, tn=v4, a=v5, b=v6
  . t=a1, n=a2
  get tn=text.n t
  . a=t+tn, a--, b=a, a+n
  .repeat tn
    . (u8) *a=*b, a--, b--
  .endr
endf

; insert text at beginning

function text.prefix, a, b
  alias a=v1, b=v2, n=v3
  . a=a1, b=a2
  get n=text.n b
  text.expand a, n
  text.write a, b
endf

; enclose t in b/egin and e/nd characters.
; example: text.enclose t, 28h, 29h
; '(', ')'

function text.enclose.c, t, b, e
  alias t=v1, b=v2, e=v3,\
   p=v4, n=v5, c=v6
  . t=a1, b=a2, e=a3
  get n=text.n t
  text.expand t, 1
  . p=t, (u8) *p=b, p=t+n, p++
  . (u8) *p++=e, (u8) *p=0
endf

; another way:

; text.copy buffer, b
; text.attach buffer, a
; text.copy a, buffer

; prefix text with c's ('0', ' ', etc)
; or ensure maximum n. example:
; before: text t='7FAB'
; text.align t, 30h, 8
; after: t='00007FAB', aligned to hex32

function text.align, t, c, n
  alias t=v1, c=v2,\
   n=v4, p=v5, tn=v6
  . t=a1, c=a2, n=a3
  get tn=text.n t
  .if n=tn            ; same size
    return            ; do nothing
  .end
  .if tn>n            ; exceeds maximum
    . t+n, (u8) *t=0  ; end at t+n
    return
  .end
  . n-tn              ; expand t
  text.expand t, n
  .repeat n
    . (u8) *t++=c
  .endr
  . t+tn, (u8) *t=0   ; terminate
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 (texts)

function text.array.equal, ta, t, n
  alias ta=v1, t=v2,\
   n=v3, i=v4, p=v5
  . ta=a1, t=a2, n=a3
  .loop i=0 to n
    . p=ta[i]
    .if.text.equal t, p ; p, t
      return i
    .end
  .endl
endf -1

macro .if.text.array.equal ta, t {
  text.array.equal ta, t, ta#.$
  .if r0<>-1
}

function text.array.begins, ta, t, n
  alias ta=v1, t=v2,\
   n=v3, i=v4, p=v5
  . ta=a1, t=a2, n=a3
  .loop i=0 to n
    . p=ta[i]
    .if.text.begins p, t
      return i
    .end
  .endl
endf -1

macro .if.text.array.begins ta, t {
  text.array.begins ta, t, ta#.$
  .if r0<>-1
}

; 2-DO: insensitive compare and search

;;;;;;;;;;;;;;;;;; CONVERSIONS ;;;;;;;;;;;;;;;;;;;

; x2t(n, t) ; number to text

; convert unsigned 32BIT integer to text

function u2t, n, t
  alias n=a1,\
   x=a2, y=a3,\
   t=v1, s=v2, c=v3
  . t=a2, s=a2
  .if n=0             ; zero?
    . (u8) *t++=30h
    . (u8) *t=0
    return t
  .end
  .while n            ; until 0
    . y=n             ; dividend
    . x=1999999Ah     ; ((2^32)/10)+1
    . n=n-(n>>>30)    ; n=n-(n>>>30)
    umull c, n, n, x  ; n*reciprocal
    . x=n<<1         
    . x=x+(x<<2)
    . x=y-x           ; remainder
    . c=x+30h         ; c=(n%10)+'0'
    . (u8) *t++=c     ; *t++=c
  .endw
  . (u8) *t=0
  text.reverse s
endf t

; convert signed 32BIT integer to text

function i2t, n, t
  alias n=a1,\
   t=a2, sign=a3
  . sign=80000000h
  .if n&sign          ; negate?
    . -n
    . (u8) *t++=2Dh   ; prepend '-'
  .end
  u2t                 ; convert
endf

; convert 32BIT hexadecimal number to text

function h2t, n, t
  alias t=v1, s=v2,\
   n=v3, x=v4, hex=v5
  . n=a1, t=a2, s=t
  . hex=_hex
  .if n=0             ; zero?
    . (u8) *t++=30h
    . (u8) *t=0
    return t
  .end
  .while n            ; *t++=*(hex+(n&(16-1)))
    . x=n&15
    ldrb x, [hex, x]  ; (u8) x=hex[x]
    . (u8) *t++=x
    . n>>>4           ; n/16
  .endw
  . (u8) *t=0
  text.reverse s
  return t
  _hex: db \
   '0123456789ABCDEF' ; 16 bytes
endf t

; convert 32BIT binary number to text

function b2t, n, t
  alias t=v1, s=v2,\
   n=v3, x=v4
  . n=a1, t=a2, s=t
  .if n=0             ; zero?
    . (u8) *t++=30h
    . (u8) *t=0
    return t
  .end
  .while n            ; *t++=(n&1)+'0'
    . x=n&1, x+30h
    . (u8) *t++=x
    . n>>>1           ; n/2
  .endw
  . (u8) *t=0
  text.reverse s
endf t

; t2x(t) ; text to number

; convert text to unsigned 32BIT integer

function t2u, t
  alias t=v1,\
   c=v2, n=v3
  . t=a1, (u8) c=*t
  .if c=30h           ; skip preceding
    .while c=30h      ; '0's...
      . (u8) c=*t++
    .endw
    . t--
  .end
  .if c=0             ; 0 value?
    return 0
  .end
  . n=0
  .forever
    . (u8) c=*t++
    .if c=0
      return n
    .end
    . n+(n<<2), n+n   ; n=n*10+*t++-'0'
    . n-30h, n+c
  .endfv
endf

; convert text to signed 32BIT integer

function t2i, t
  alias t=v1,\
   c=v2, negate=v3
  . t=a1, (u8) c=*t
  . negate=0
  .if c='-'           ; negative?
    . t++, negate=1   ; skip
  .end
  t2u t
  .if negate
    . -a1
  .end
endf

; convert hexadecimal text to number

function t2h, t       ; text to hexadecimal
  alias t=v1,\
   c=v2, n=v3
  . t=a1, (u8) c=*t
  .if c=30h           ; skip preceding
    .while c=30h      ; '0's...
      . (u8) c=*t++
    .endw
    . t--
  .end
  .if c=0             ; 0 value?
    return 0
  .end
  . n=0
  .forever
    . (u8) c=*t++
    .if c=0
      return n
    .end
    . n<<4            ; n=n*16+c2h(*t++)
    .if c<=39h        ; 0-9
      . c-30h
    .else.if c>=97    ; a-f
      . c-57h
    .else             ; A-F
      . c-37h
    .end
    . n+c
  .endfv
endf

; convert binary text to number

function t2b, t       ; text to binary
  alias t=v1,\
   c=v2, n=v3
  . t=a1, (u8) c=*t
  .if c=30h           ; skip preceding
    .while c=30h      ; '0's...
      . (u8) c=*t++
    .endw
    . t--
  .end
  .if c=0             ; 0 value?
    return 0
  .end
  . n=0
  .forever
    . (u8) c=*t++
    .if c=0
      return n
    .end
    . n<<1, n+c       ; n=n*2+*t++-'0'
    . n-30h
  .endfv
endf

;;;;;;;;;;;;;;;;;;;;; PRINT ;;;;;;;;;;;;;;;;;;;;;;

; 2-DO: print formatted text to buffer

;;;;;;;;;;;;;;;;;;; PARSE TEXT ;;;;;;;;;;;;;;;;;;;

; skip while type and not 0

; get p=text.skip.while p, C.WHITE

function text.skip.while, t, type
  alias t=a1, type=a2,\
   c=a3, p=a4, n=v1
  .forever
    . (u8) c=*t
    .if c=0
      return 0
    .end
    .if c=0Ah
      . p=line.n, (u32) n=*p
      . n++, (u32) *p=n
    .end
    . p=TLT, p+c
    . (u8) c=*p, c&type
    .breakz
    . t++
  .endfv
  . (u8) c=*t
  .if c=0
    return 0
  .end
endf

; skip until type and while not 0

; get p=text.skip.until p, C.RETURN

function text.skip.until, t, type
  alias t=a1, type=a2,\
   c=a3, p=a4, n=v1
  .forever
    . (u8) c=*t
    .if c=0
      return 0
    .end
    .if c=0Ah
      . p=line.n, (u32) n=*p
      . n++, (u32) *p=n
    .end
    . p=TLT, p+c
    . (u8) c=*p, c&type
    .breakn
    . t++
  .endfv
  . (u8) c=*t
  .if c=0
    return 0
  .end
endf

; copy while type and not 0

; get s=text.copy.while t, s, C.NAME

function text.copy.while, a, b, type
  alias a=a1, b=a2,\
   type=a3, c=a4, p=v1, n=v2
  .forever
    . (u8) c=*b
    .if c=0
      go .e
    .end
    .if c=0Ah
      . p=line.n, (u32) n=*p
      . n++, (u32) *p=n
    .end
    . p=TLT, p+c
    . (u8) c=*p, c&type
    .breakz
    . (u8) *a++=*b++
  .endfv
  .e:
  . (u8) *a=0, (u8) c=*b
  .if c=0
    return 0
  .end
endf b

; copy until type and while not 0

; get s=text.copy.until t, s, C.END

function text.copy.until, a, b, type
  alias a=a1, b=a2,\
   type=a3, c=a4, p=v1, n=v2
  .forever
    . (u8) c=*b
    .if c=0
      return 0
    .end
    .if c=0Ah
      . p=line.n, (u32) n=*p
      . n++, (u32) *p=n
    .end
    . p=TLT, p+c
    . (u8) c=*p, c&type
    .breakn
    . (u8) *a++=*b++
  .endfv
  . (u8) *a=0, (u8) c=*b
  .if c=0
    return 0
  .end
endf b

;;;;;;;;;;;;;;;;;; SOURCE, TOKEN ;;;;;;;;;;;;;;;;;

; safer, easier global skip/copy while/until

macro define.source {
 align 4
 void source.p, destiny.p, token.p
 integer token.type, token.value,\
  token.size, line.n, n.lines
}

macro set.source r
 { . r12=source.p, r11=r, (u32) *r12=r11 }

macro set.token r
 { . r12=token.p, r11=r, (u32) *r12=r11 }

macro set.stream s, t {
  set.source s
  set.token t
}

macro get.source s, t {
  . s=source.p, (u32) s=*s
  if ~t eq
    . t=token.p, (u32) t=*t
  end if
}

; 2-DO...

get.destiny fix get.console
set.destiny fix set.console
save.destiny fix save.console

macro get.token.p t
 { . t=token.p, (u32) t=*t }

macro set.token.x x, v
 {  . r12=token#x, r11=v, (u32) *r12=r11 }

macro set.token.type v { set.token.x .type, v }
macro set.token.class v { set.token.x .class, v }
macro set.token.value v { set.token.x .value, v }

macro get.token.value x
{ . x=token.value, (u32) x=*x }

; skip/copy while/until type...

function skip.while, type
  alias p=v1, type=v2
  . type=a1
  get.source p
  try p=text.skip.while p, type
  set.source p
endf p

function skip.until, type
  alias p=v1, type=v2
  . type=a1
  get.source p
  try p=text.skip.until p, type
  set.source p
endf p

function copy.while, type
  alias p=v1, t=v2, type=v3
  . type=a1
  get.source p, t
  try p=text.copy.while t, p, type
  set.source p
endf p

function copy.until, type
  alias p=v1, t=v2, type=v3
  . type=a1
  get.source p, t
  try p=text.copy.until t, p, type
  set.source p
endf p

macro skip.space   { skip.while C.SPACE }
macro skip.white   { skip.while C.WHITE }
macro skip.comment { skip.until C.RETURN }

function skip.all
  alias s=v1, c=v2
  .white:
  try skip.white
  get.source s
  . (u8) c=*s
  .if c=0
    return 0
  .end
  .if c=SEMI.C
    try skip.comment
    go .white
  .end
endf 1

; skip spaces then character. return 0
; if next c not key

function skip.c, key
  alias p=v1,\
   c=v2, key=v3
  . key=a1
  skip.space
  get.source p
  . (u8) c=*p
  .if c<>key
    return 0
  .end
  . p++
  set.source p
endf p

; ideas for parsing grammar:

; syntax: parse 'c' ; c=command/s

; '='      ; copy
; '>'      ; skip forward
; '<'      ; skip reverse
; '>1'     ; move right # times
; '<1'     ; move left # times
; '>ws'    ; skip while space/tab
; '>ur'    ; skip until return
; '>w_'    ; skip all whitespace
; '>w;'    ; skip all+comments
; '=u.'    ; copy until end/delimiter
; '=w#'    ; while digit
; '=w@'    ; while name/identifier
; '>w_=u.' ; skip whitespace then copy

; '=w(a-z|A-Z|0-9|_|.|?)'    
Post 09 Apr 2014, 15:56
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.