flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > 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
[ARM] Reusable Binary Modules: Import+Export Library
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 strlenstrcpystrcmpstrequ

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

function strlens
  alias s=a1b=a2c=v1
  . c=1b=s
  .while c           ; until 0
    . (u8c=*s++    ; read c
  .endw
  . s--, s-b         ; return current-start
endf

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

function strcpyab
  alias a=a1b=a2c=v1
  . c=1
  .while c
    . (u8c=*b++    ; read
    . (u8) *a++=c    ; copy
  .endw
  . a--              ; return end
endf

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

function strcmpab
  alias a=a1b=a2,\
   c=v1d=v2
   . c=1d=c
  .while c=d         ; while equal
    . (u8c=*a++
    . (u8d=*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 strequab
  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,\
 strlenstrcpystrcmpstrequ

; example code...

nop
strcpy 12
strcmp 12

DISASSEMBLY OF STRING+DRAW

Syntaxes generate highly optimized ARM assembler:

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

; Disassembly of DRAW.L:

00000000 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000004 E3A02000 mov    a30
00000008 E3822C05 orr    a3a3500h
0000000C E0130291 muls   a4a2a3
00000010 E0933080 adds   a4a4a1lsl 1
00000014 E3A01000 mov    a20
00000018 E3811602 orr    a2a2200000h
0000001C E0910003 adds   a1a2a4
00000020 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000024 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000028 E3A02000 mov    a30
0000002C E3822602 orr    a3a3200000h
00000030 E3A01000 mov    a20
00000034 E3811A0B orr    a2a20B000h
00000038 E3811701 orr    a2a240000h
0000003C E3510000 cmp    a20
00000040 0A000002 beq    50h
00000044 E0C200B2 strh   a1, [a3], 2
00000048 E2511001 subs   a2a21
0000004C EAFFFFFA b      3Ch
00000050 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000054 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000058 E1A04002 mov    v1a3
0000005C E92D000F stmdb  sp!, {a1-a4}
00000060 E3A02000 mov    a30
00000064 E3822C05 orr    a3a3500h
00000068 E0130291 muls   a4a2a3
0000006C E0933080 adds   a4a4a1lsl 1
00000070 E3A01000 mov    a20
00000074 E3811602 orr    a2a2200000h
00000078 E0910003 adds   a1a2a4
0000007C E1A0A000 mov    v7a1
00000080 E8BD000F ldmia  sp!, {a1-a4}
00000084 E1A0000A mov    a1v7
00000088 E1C040B0 strh   v1, [a1]
0000008C E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000090 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000094 E1A04003 mov    v1a4
00000098 E1A05002 mov    v2a3
0000009C E92D000F stmdb  sp!, {a1-a4}
000000A0 E3A02000 mov    a30
000000A4 E3822C05 orr    a3a3500h
000000A8 E0130291 muls   a4a2a3
000000AC E0933080 adds   a4a4a1lsl 1
000000B0 E3A01000 mov    a20
000000B4 E3811602 orr    a2a2200000h
000000B8 E0910003 adds   a1a2a4
000000BC E1A0A000 mov    v7a1
000000C0 E8BD000F ldmia  sp!, {a1-a4}
000000C4 E1A0000A mov    a1v7
000000C8 E3550000 cmp    v20
000000CC 0A000002 beq    0DCh
000000D0 E0C040B2 strh   v1, [a1], 2
000000D4 E2555001 subs   v2v21
000000D8 EAFFFFFA b      0C8h
000000DC E8BD9FF0 ldmia  sp!, {v1-ip,pc}
000000E0 E92D5FF0 stmdb  sp!, {v1-ip,lr}
000000E4 E1A04003 mov    v1a4
000000E8 E1A05002 mov    v2a3
000000EC E92D000F stmdb  sp!, {a1-a4}
000000F0 E3A02000 mov    a30
000000F4 E3822C05 orr    a3a3500h
000000F8 E0130291 muls   a4a2a3
000000FC E0933080 adds   a4a4a1lsl 1
00000100 E3A01000 mov    a20
00000104 E3811602 orr    a2a2200000h
00000108 E0910003 adds   a1a2a4
0000010C E1A0A000 mov    v7a1
00000110 E8BD000F ldmia  sp!, {a1-a4}
00000114 E1A0000A mov    a1v7
00000118 E3550000 cmp    v20
0000011C 0A000003 beq    130h
00000120 E0D4C0B2 ldrh   ip, [v1], 2
00000124 E0C0C0B2 strh   ip, [a1], 2
00000128 E2555001 subs   v2v21
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 00       ; reserved
 forward        ; array of:
  local l
  l db `f0    ; 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 abc,\
   pinso,\
   fbfoundequal
  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 `f0               ; name
   times \                ; align 24
    24-($-idb 0
   dw 00                ; 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: 2171 Time(s)

library.gif


Description:
Download
Filename: arm_library.zip
Filesize: 124.98 KB
Downloaded: 312 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
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.cctype
  . a1&0FFha3=TLTa3+a1
  . (u8a1=*a3a1&a2
endf

macro is.c ct {
  . a1=ca2=t
  is.c
}

macro if.is ct {
  is.c cC.#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 ab
 { !if text.equalab }
macro .if.not.text.equal ab
 { !if.n text.equalab }
macro .if.text.find ab
 { !if text.findab }
macro .if.text.find.last ab
 { !if text.find.lastab }
macro .if.text.begins ab
 { !if text.beginsab }
macro .if.text.ends ab
 { !if text.endsab }

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

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

function text.endt
  alias t=a1c=v1
  . c=1
  .while c           ; until 0
    . (u8c=*t++    ; read c
  .endw
  . t--
endf

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

function text.nt
  alias t=a1b=a2c=v1
  . c=1b=t
  .while c           ; until 0
    . (u8c=*t++    ; read c
  .endw
  . t--, t-b         ; return current-start
endf

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

function text.writeab
  alias a=a1b=a2c=v1
  .forever
    . (u8c=*b++    ; read
    .if c=0
      return
    .end
    . (u8) *a++=c    ; copy
  .endfv
endf

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

function text.copyab
  alias a=a1b=a2c=v1
  . c=1
  .while c
    . (u8c=*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.nabn
  alias a=a1b=a2,\
   n=a3c=v1
  .repeat n          ; # times
    . (u8c=*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.attachab
  alias a=a1,\
   b=a2p=v1
  . p=b
  text.end
  . b=p
  text.copy
endf

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

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

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

function text.compareab
  alias a=a1b=a2,\
   c=v1d=v2
   . c=1d=c
  .while c=d         ; while equal
    . (u8c=*a++
    . (u8d=*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.equalab
  text.compare
  .if false
    return 1
  .end
endf 0

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

function text.findtc
  alias t=a1,\
   c=v1key=a2
  .forever           ; loop
    . (u8c=*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.lasttc
  alias t=a1c=a2,\
   key=v1p=v2
  . key=cp=t       ; save begin
  . c=1
  .while c           ; advance to end-1,
    . (u8c=*t++    ; last character
  .endw
  . t-2
  .while t>p         ; loop backwards
    . (u8c=*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.ctc
  alias p=v1c=v2n=v3
  . p=a1c=a2n=0
  .while true
    get p=text.find pc
    .if true
      . p++, n++
    .end
  .endw
endf n

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

function text.count.nt
  text.count.c a10Dh
  .if a1>0
    . a1++
  .end
endf

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

function text.beginsab
  alias a=a1b=a2,\
   c=v1d=v2e=v3
  . c=1d=c
  .while c=d         ; while equal
    . (u8c=*a++    ; load *a/*b
    . (u8d=*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.endsab
  alias \
   a=v1b=v2p=v3
  . a=a1b=a2
  text.end            ; a=end(a)-length(b)
  . p=a1a1=b
  text.n
  . p-a1a1=pa2=b
  text.compare
  .if false
    return 1
  .end
endf 0

; text.upper(t) - convert to uppercase

function text.uppert
  alias t=a1c=v1
  .forever
    . (u8c=*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.lowert
  alias t=a1c=v1
  .forever
    . (u8c=*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.reverset
  alias t=a1,\
   p=a2s=a3,\
   c=v1d=v2
  . s=tc=1         ; save start
  .while c
    . (u8c=*t++    ; advance to end
  .endw
  . p=t-2t=s
  .while t<p         ; exchange *t++/*p--
    . (u8c=*t
    . (u8d=*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.expandtn
  alias t=v1p=v2,\
   n=v3tn=v4a=v5b=v6
  . t=a1n=a2
  get tn=text.n t
  . a=t+tna--, b=aa+n
  .repeat tn
    . (u8) *a=*ba--, b--
  .endr
endf

; insert text at beginning

function text.prefixab
  alias a=v1b=v2n=v3
  . a=a1b=a2
  get n=text.n b
  text.expand an
  text.write ab
endf

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

function text.enclose.ctbe
  alias t=v1b=v2e=v3,\
   p=v4n=v5c=v6
  . t=a1b=a2e=a3
  get n=text.n t
  text.expand t1
  . p=t, (u8) *p=bp=t+np++
  . (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.aligntcn
  alias t=v1c=v2,\
   n=v4p=v5tn=v6
  . t=a1c=a2n=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 tn
  .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.equaltatn
  alias ta=v1t=v2,\
   n=v3i=v4p=v5
  . ta=a1t=a2n=a3
  .loop i=0 to n
    . p=ta[i]
    .if.text.equal tp ; p, t
      return i
    .end
  .endl
endf -1

macro .if.text.array.equal tat {
  text.array.equal tatta#.$
  .if r0<>-1
}

function text.array.beginstatn
  alias ta=v1t=v2,\
   n=v3i=v4p=v5
  . ta=a1t=a2n=a3
  .loop i=0 to n
    . p=ta[i]
    .if.text.begins pt
      return i
    .end
  .endl
endf -1

macro .if.text.array.begins tat {
  text.array.begins tatta#.$
  .if r0<>-1
}

; 2-DO: insensitive compare and search

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

; x2t(n, t) ; number to text

; convert unsigned 32BIT integer to text

function u2tnt
  alias n=a1,\
   x=a2y=a3,\
   t=v1s=v2c=v3
  . t=a2s=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 cnnx  ; 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 i2tnt
  alias n=a1,\
   t=a2sign=a3
  . sign=80000000h
  .if n&sign          ; negate?
    . -n
    . (u8) *t++=2Dh   ; prepend '-'
  .end
  u2t                 ; convert
endf

; convert 32BIT hexadecimal number to text

function h2tnt
  alias t=v1s=v2,\
   n=v3x=v4hex=v5
  . n=a1t=a2s=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, [hexx]  ; (u8) x=hex[x]
    . (u8) *t++=x
    . n>>>4           ; n/16
  .endw
  . (u8) *t=0
  text.reverse s
  return t
  _hexdb \
   '0123456789ABCDEF' ; 16 bytes
endf t

; convert 32BIT binary number to text

function b2tnt
  alias t=v1s=v2,\
   n=v3x=v4
  . n=a1t=a2s=t
  .if n=0             ; zero?
    . (u8) *t++=30h
    . (u8) *t=0
    return t
  .end
  .while n            ; *t++=(n&1)+'0'
    . x=n&1x+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 t2ut
  alias t=v1,\
   c=v2n=v3
  . t=a1, (u8c=*t
  .if c=30h           ; skip preceding
    .while c=30h      ; '0's...
      . (u8c=*t++
    .endw
    . t--
  .end
  .if c=0             ; 0 value?
    return 0
  .end
  . n=0
  .forever
    . (u8c=*t++
    .if c=0
      return n
    .end
    . n+(n<<2), n+n   ; n=n*10+*t++-'0'
    . n-30hn+c
  .endfv
endf

; convert text to signed 32BIT integer

function t2it
  alias t=v1,\
   c=v2negate=v3
  . t=a1, (u8c=*t
  . negate=0
  .if c='-'           ; negative?
    . t++, negate=1   ; skip
  .end
  t2u t
  .if negate
    . -a1
  .end
endf

; convert hexadecimal text to number

function t2ht       ; text to hexadecimal
  alias t=v1,\
   c=v2n=v3
  . t=a1, (u8c=*t
  .if c=30h           ; skip preceding
    .while c=30h      ; '0's...
      . (u8c=*t++
    .endw
    . t--
  .end
  .if c=0             ; 0 value?
    return 0
  .end
  . n=0
  .forever
    . (u8c=*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 t2bt       ; text to binary
  alias t=v1,\
   c=v2n=v3
  . t=a1, (u8c=*t
  .if c=30h           ; skip preceding
    .while c=30h      ; '0's...
      . (u8c=*t++
    .endw
    . t--
  .end
  .if c=0             ; 0 value?
    return 0
  .end
  . n=0
  .forever
    . (u8c=*t++
    .if c=0
      return n
    .end
    . n<<1n+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.whilettype
  alias t=a1type=a2,\
   c=a3p=a4n=v1
  .forever
    . (u8c=*t
    .if c=0
      return 0
    .end
    .if c=0Ah
      . p=line.n, (u32n=*p
      . n++, (u32) *p=n
    .end
    . p=TLTp+c
    . (u8c=*pc&type
    .breakz
    . t++
  .endfv
  . (u8c=*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.untilttype
  alias t=a1type=a2,\
   c=a3p=a4n=v1
  .forever
    . (u8c=*t
    .if c=0
      return 0
    .end
    .if c=0Ah
      . p=line.n, (u32n=*p
      . n++, (u32) *p=n
    .end
    . p=TLTp+c
    . (u8c=*pc&type
    .breakn
    . t++
  .endfv
  . (u8c=*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.whileabtype
  alias a=a1b=a2,\
   type=a3c=a4p=v1n=v2
  .forever
    . (u8c=*b
    .if c=0
      go .e
    .end
    .if c=0Ah
      . p=line.n, (u32n=*p
      . n++, (u32) *p=n
    .end
    . p=TLTp+c
    . (u8c=*pc&type
    .breakz
    . (u8) *a++=*b++
  .endfv
  .e:
  . (u8) *a=0, (u8c=*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.untilabtype
  alias a=a1b=a2,\
   type=a3c=a4p=v1n=v2
  .forever
    . (u8c=*b
    .if c=0
      return 0
    .end
    .if c=0Ah
      . p=line.n, (u32n=*p
      . n++, (u32) *p=n
    .end
    . p=TLTp+c
    . (u8c=*pc&type
    .breakn
    . (u8) *a++=*b++
  .endfv
  . (u8) *a=0, (u8c=*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.pdestiny.ptoken.p
 integer token.typetoken.value,\
  token.sizeline.nn.lines
}

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

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

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

macro get.source st {
  . s=source.p, (u32s=*s
  if ~t eq
    . t=token.p, (u32t=*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, (u32t=*t }

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

macro set.token.type v { set.token.x .typev }
macro set.token.class v { set.token.x .classv }
macro set.token.value v { set.token.x .valuev }

macro get.token.value x
. x=token.value, (u32x=*x }

; skip/copy while/until type...

function skip.whiletype
  alias p=v1type=v2
  . type=a1
  get.source p
  try p=text.skip.while ptype
  set.source p
endf p

function skip.untiltype
  alias p=v1type=v2
  . type=a1
  get.source p
  try p=text.skip.until ptype
  set.source p
endf p

function copy.whiletype
  alias p=v1t=v2type=v3
  . type=a1
  get.source pt
  try p=text.copy.while tptype
  set.source p
endf p

function copy.untiltype
  alias p=v1t=v2type=v3
  . type=a1
  get.source pt
  try p=text.copy.until tptype
  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=v1c=v2
  .white:
  try skip.white
  get.source s
  . (u8c=*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.ckey
  alias p=v1,\
   c=v2key=v3
  . key=a1
  skip.space
  get.source p
  . (u8c=*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


Powered by phpBB © 2001-2005 phpBB Group.

Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2016, Tomasz Grysztar.