/*
  LINK.INC

  O2 COMPILER SEED AND LINKER
  ===========================

  INSTRUCTION SET
  ---------------


  SYMBOL  DESCRIPTION

  .    label
  .bssdata  start of uninitialised data section (and end of initialised data)

  '  line comment
  ;  line comment


  "    byte char quotes
  w"   wide char quotes

  $    pad with null bytes '00' use headecimal
  $$   pad space and align to nearest 4 bytes
       use hexadecimal


  !    align to next n (NOP '90' padding in haxadecimal !10 == 16 byte alignment)
       use hexadecimal

  /    set position from start of code (pad with nulls)
  /+   round-up position to next n (pad with nulls)
       use hexadecimal

  ( )  block delimiters


  NUMBER PREFIXES
 
  nb   decimal byte
  nw   decimal word
  nl   decimal dword/long
  nq   decimal quad
  ng   decimal long/quad according to 32bit/64bit platform

  ns   decimal single floating point
  nd   decimal double floating point

  hb   hexadecimal byte
  hw   hexadecimal word
  hl   hexadecimal long
  hq   hexadecimal quad
  hg   hexadecimal long/quad according to 32bit/64bit platform


  00..ff   hexadecimal bytes
  000..377 octal bytes


  LABEL / BLOCK  JUMPS

  x    exit block, short relative
  xl   exit block, long relative
  r    repeat block, short relative
  rl   repeat block, long long relative
  g    short relative
  gl   long relative
  gf   long relative forward
  ga   long (relative from start of codestring (absolute)
  gq   quad (relative from start of codestring (absolute)
  gg   long/quad according to 32bit/64bit platform

  DATA LINKAGE

  gc   code side index
  gd   data side index


  MARK

  m    mark (remark) non-exec info till end of line
 
  POSITION

  p 1..n record position offset from start of code

 
  OTHERS

  k    namespace
  q    raw embedded file
  z    zap last instance of label

*/

int gbo  'linked binary output
int gelb 'link buffer extensions
int bkmx 'max label count

procedure stretchbuffer(string*s, int i)
========================================
int le=len(s)
if i+4096>le
  s+=nuls i-le+0x8000
  gelb++
endif
end procedure

% sizli 16383
'
string xn[sizli]  'forward ref
string xf[sizli]  'file name
'
type bakref
  int p
  int d
  int l
  int n
  string w
end type
'
type fwdref
  int p
  int c
  int d
  int m
  int n
  int l
end type
'
function HexLink(string*s) as string
====================================
'
' VARIABLES
'
' a      ascii byte
' b      general purpose
' c      general purpose
' d      general purpose
' i      source string position
' j      code position
' k      general purpose
' l      length of source
' m      general purpose
' n      general purpose
' s      source  string
' t      code string
' u      general purpose
' v      general purpose
' w      general purpose
' nb()   starting position of current block
'
' xi()   attributes of foward reference
' .p  0    location to patch
' .c  1    first 2 name chars
' .d  2    depth
' .m  3    link mode
' .n  4    namespace
' .l  5    line number
' xn()   label names
' xf()   file names
'
' bk().w label name
' bk().p position of label
' bk().d nesting depth of label
' bk().l line number of label
' bk().n namespace of label
' bke    label list boundary
' bkmx   max labels used in nestings
'
' neb    current nesting depth
' wd     general purpose word
' ke     keyword
' nsi    namespace index
' lln    last line number
'
' ert    global error type
' ers    global error message string
'
'BUFFERS
'
static int nb[127]
static bakref bk[sizli]
static fwdref fw[sizli]
'
string t
string wd,ke,lnkn, fnmks
int    neb, xib, bke, lnki, lnkj, lnkk, bss
int    a,b,c,d,i,j,k,m,n,u,v,w,l,lln
sys    pm,pt,qt
nsi=0
i=1
j=1
l=len(s)
t=nuls(l*4)

ert=0
lnki=0

byte bb at strptr(s)-1


'putfile "t.txt",s

'================
'MAIN READER LOOP
'================

linkloop:
'
do ' main loop
  '
  do ' skip space for next word 
      if (i>l)or(bb(i)>32)
        exit do
      endif
      i++
  loop
  if i>l
    exit do
  endif
  '
  stretchbuffer(t,j)
  '
  '---------------
  'INTERPRET CASES
  '===============
  ' 
  do ' case interpret word
    a=ascl(s,i)


    a=ascl(s,i)
    '
    '
    'CHECK FOR VALUES
    select a
    case 0x30 to 0x39 : a=48
    case 0x41 to 0x46 : a=48
    case 0x61 to 0x66 : a=48
    end select
    '
    select a
    '
    case 48
    '
    'OCTAL BYTE
    '==========
    '
    if i+2<l 'octal byte
      if bb(i+2)>47
        mid(t,j)=chr(val("&o"+mid(s,i,3)))
        i+=3
        j++
        goto linkloop
      endif
    endif
    '
    '
    'HEX BYTE
    '================
    '
    pt=strptr(t)
    qt=strptr(s)
    '
    mov rcx,qt
    add rcx,i
    dec rcx 'offset
    dec rcx 'align for hexaval
    mov rsi,pt
    add rsi,j
    dec rsi 'offset
    call hexaval
    mov [rsi],al
    '
    i+=2
    j++
    goto linkloop
    '
    '
    'HOST SYMBOLS
    '============
    '
    '# variable address
    '
    case 35
    '
    m=i
    do
      i++
      if i>l
        exit do
      endif
      a=bb(i)
      if a<48
        exit do
      endif
    loop
    wd=mid(s,m,i-m) : m=0
    if wd
      pm=GetVarPtr(wd)
    endif
    if pm=0
      ers="Can't find #symbol: "+wd : ert=5 : goto exitf
    endif
    mk4(t,j,m) : j+=4 ' patch in var addr
    exit do
    '
    'LINE COMMENTS
    '=============
    '
    case ct1,ct2
    '
    i++
    ascn=bb(i)
    if ascn=95
      swd=i+1 : endline(s,i) : wd=mid(s,swd,i-swd) '_n
      a=asc(wd)
      if isn(a)
        lln=wd
      else
        fnmks=wd
      endif
    endif
    endline(s,i) : exit do
    '
    '
    'IGNORED SYMBOLS / PUNCTUATION
    '=============================
    '
    case 44  : exit do ' skip comma
    '
    case sr1 : exit do ' skip separator (colon / semicolon)
    '
    '
    'QUOTED STRINGS
    '==============
    '
    'WIDE STRING CONVERSION
    '
    case 0x77 ' w"  w`
    '
    b=ascl(s,i+1)
    if isq(b)
      c=i+1 : wd=aword(s,c)
      stretchbuffer(t,j+4096+lenw*2)
      i+=2
      do
        if i>l
          exit do
        endif
        a=bb(i)
        if a=b
          i++ : exit do
        endif
        mid(t,j)=chr(a)+chr(0) : j+=2
        i++
      loop
      exit do 'cases
    endif
    '
    '
    '
    'NOP ALIGNMENT PADDING
    '=====================
    '
    ' ! align to mod m by filling with nops
    '
    case 33
    '
    m=val("0x"+mid(s,i+1,8)) 'HEXADECIMAL
    v=(j-1) and (m-1)
    v=m-v
    if v<m
      stretchbuffer(t,j+v)
      mid(t,j)=string(v,chr(0x90))
      j+=v 'round up
    endif
    exit do
    '
    '
    '$ MAKE BLOCK OF NULLS $$ ALIGNED UP TO 16 BYTES
    '===============================================
    '
    case 36 ' $ reserve space 
    '
    m=0
    if bb(i+1)=36
      m=16 : i++ ' $$ ALIGN  UP TO 16
    endif
    v=val("0x"+mid(s,i+1,9)) 'VALUE ASSUMED HEXADECIMAL
    a=j
    j+=v
    if m
      v=(j-1) and (m-1) ' HEX MODULUS
      v=m-v
      if v<m
        j+=v
      endif
    endif
    stretchbuffer(t,j)
    midnuls(t,a,j)
    exit do
    '
    '
    '/ SET ADDRESS OR /+ ALIGNMENT OFFSET
    '====================================
    '
    case 47 ' / set offset
    '
    i++
    a=bb(i)
    if a=43
      i++
    endif
    v=val("0x"+mid(s,i,8)) 'VALUE ASSUMED HEXADECIMAL
    if a=43
      v=((j-1) \ v) * v + v 'round up with v even when already aligned
    endif
    if j>v+1
      ert=22
      ers="Location already occupied "+hex(v)+" p"+hex(j)
      goto exitf
    endif
    stretchbuffer(t,j+v)
    j=v+1
    exit do
    '
    '
    'm MARK (non encoding)
    '======
    '
    case 0x6d 'm
    '
    i++
    endline(s,i)
    exit do
    '
    '
    'o MORE OXYGEN
    ==============
    '
    case 0x6f
    '
    i+=2
    continue do

    'p POSITION (record position)
    '==========
    '
    case 0x70 'p1 p2 p3 etc.decimal index
    '
    'standard usage:
    'p2  end of code section
    'p3  end of init data section
    'p4  end of uninit data section
    'p5  end of export section
    'p6  end of import section
    i++
    a=readint(s,i)
    posbin(a)=j-1
    'print a tab j-1
    exit do
    '
    'q RAW BINARY EMBEDDED FILE
    ===========================
    '
    case 0x71
    '
    i++
    string wf,sf
    wf=noquotes(aword(s,i))
    sf=getfile(wf)
    a=len sf
    if not a
      ers="not embedded: "+wf+" " : ert=6 : goto exitf
    endif
    stretchbuffer(t,j+a)
    mid(t,j)=sf
    j+=a
    continue do


    '
    'k NAMESPACE
    '===========
    '    
    case 0x6b 'k
    '
    i++
    nsi=hexval(s,i) 'namespace number
    exit do
    '
    '
    '
    case 40 '( BEGINNING OF NEST
    '
    neb++
    nb(neb)=j
    i++
    exit do
    '
    case 41 ') END OF NEST
    '
    'disallocate inner labels
    'except global labels
    b=bke
    do
      b--
      if b<0
        exit do
      endif
      m=bk(b).d
      if m<neb
        exit do
      endif
    loop
    bke=b+1
    '
    end select
    '
    'ASCII STRING
    '============
    '
    '
    if isq(a) ' quote types
      m=i+1
      do
        i++
        if i>l
          exit do
        endif
        if bb(i)=a
          exit do
        endif
      loop
      mid(t,j)=mid(s,m,i-m) : j+=i-m : i++
      exit do ' cases
    endif
    '
    '
    '------------------------
    'END-OF-NEST OR DOT LABEL
    '========================
    '
    if (a=rbr)or(a=46) ') . fwd refs only
      ke=""
      '
      'LABELS
      '------
      '
      c=0
      n=neb
      if a=46 
        i++ : ke=aword(s,i)
        '        '
        ascw=asc(ke)
        if ascw=0x62
          if ke="bssdata"
            bss=j 'offset of bss (uninitialised data section)
          endif
        endif
        i-=2
        v=ascl(ke,1)*256 : a=ascl(ke,2)
        if a<48
          a=32
        endif
        v+=a ' 2 significant letters
        '
        'REGISTER LABEL
        n=neb
        bakref bkk at @bk(bke)
        bkk.w=ke     'label name
        bkk.d=n      'nesting depth
        bkk.p=j      'binary position
        bkk.n=nsi    'namespace
        bkk.l=lln    'last line number
        bke++            '
        if bkmx<bke
          bkmx=bke
        endif
        a=v
      endif
      '
      '
      '--------------------
      'RESOLVE FORWARD REFS
      '====================
      '
      if xib>0
        v=xib-1
        '
        '-------------------
        'SCAN FWD REFS TABLE
        '===================
        '
        do
          if v<0
            exit do
          endif
          '
          d=0                'OK FLAG
          b=fw(v).n        'FORWARD REFERENCE NAMESPACE
          if b=nsi
            d=1            'MATCHING IMPLICIT NAMESPACE
          elseif c=0
            d=1            'ACCEPTING NULL NAME SPACE
          endif
          '
          'n is neb
          if (fw(v).c=a)and(fw(v).d>=n)and(d<>0)and(xn(v)=ke)
            '
            'FWD REF RECORD IDENTIFIED
            '-------------------------
            '
            m=fw(v).p 'LOCATION TO PATCH
            '
            do
              '
              'CHECK LONG / QUAD ADDRESSES
              '--------------------
              '
              w=fw(v).m 'LINK MODE
              '
              if m<0
                '
                select w
                '
                case 0x61 'LONG LINKAGE 'A'
                  '
                  mk4(t,-m,j-1)
                  exit do 'ABSOLUTE (OFFSET FROM 0) 32 BITS
                  '
                case 0x71 'QUAD LINKAGE 'Q'
                  '
                  mk8(t,-m,j-1)
                  exit do  'ABSOLUTE (OFFSET FROM 0) 64 BITS
                  '
                case else 'L' LONG RELATIVE 'F' LONG FORWARD RELATIVE
                  '
                  mk4(t,-m,j+m-4)
                  exit do 'RELATIVE ADDRESS
                  '
                end select
                '
              endif 'm<0
              '
              'OTHERWISE SHORT LINKAGE
              '-----------------------
              '
              n=(j-m-1)
              '
              if (n<0)or(n>127)
                ers=ke+" Jump out of range (-128..+127) "+str(n)
                ert=2 : goto exitf
              endif
              mid(t,m)=chr(n)
              exit do
            loop 'END OF CASES
            '
            'CLEAR RECORD ON RESOLVED LINKS
            '
            fw(v).c=0
            fw(v).d=0
            xn(v)="" 
          endif
          v--
        loop 'END OF FWD REFS LINKs
        '
        '
        'CONSOLIDATE FWD REFS LIST
        '=========================
        '
        v=0 : m=0
        do
          m++
          if fw(v).c<>0
            '
            'transfer reference to a lower nesting level
            '
            if a=rbr
              if fw(v).d>=neb
                fw(v).d=neb-1
              endif
            endif
            v++ : continue do 'PRESERVE
          endif
          if m>=xib
            exit do 'END OF LIST
          endif
          int mi=m
          int vi=v
          if fw(mi).c=0
            continue do 'M EMPTY
          endif
          '
          copy @fw+vi*24,@fw+mi*24,24 '6 attributes
          '
          xn(v)=xn(m)
          xf(v)=xf(m)
          if a=rbr
            if fw(vi).d>=neb
              fw(vi).d=neb-1
            endif
          endif
          init4 @fw(mi),6,0
          xn(m)="" ' clear m
          v++
        loop
        xib=v
      endif
      '
      '
      'CHECK FOR CLOSE OF NESTING
      '==========================
      '
      if a=rbr
        neb-- ' )
        if neb<0
          ers="Linker found too many right brackets "+
            fnmks " " lln
          ert=4 : goto exitf
        endif
        '
        '
        'CONSOLIDATE BACK LIST
        '=====================
        '
        'remove label references that were within the nest
        '
        v=0 : m=0
        do
          if m>=bke
            exit do
          endif
          if bk(m).d>neb
            m++ : continue do 'REMOVE
          endif
          if m>v 
            bakref bkk at @bk(v)
            bakref bkm at @bk(m)
            bkk.w=bkm.w
            bkk.p=bkm.p
            bkk.n=bkm.n
            bkk.d=bkm.d
            bkk.l=bkm.l
            bkm.w=""
          endif
          v++ : m++
        loop
        bke=v
      endif
      i++ : exit do
    endif
    '
    m=ascl(s,i+1)
    '
    '
    'G JUMP ADDRESSES ETC
    '====================
    '
    if a=0x67
      '
      i++
      if m>32
        i++
      endif
      ke=aword(s,i)
      '
      i--
      v=ascl(ke,1)*256 : a=ascl(ke,2)
      if a<48
        a=32
      endif
      v+=a ' 2 significant letters, initial search filter
      '
      'G INTERPRETATION
      '================
      '
      b=bke
      '
      'LINKAGE MODES
      '-------------
      '
      select m
      case 0x66 : b=0 : m=0x6c 'GF' LONG FWD REF ONLY
      case 0x73 : b=0 : m=0x00 'GS' SHORT FWD REF ONLY
      case 0x63 :              'GC' CODE SIDE DATA LINK
        appe(lnkc,lnki,"    ") : mk4(lnkc,lnki-3,j)            'LINK ADDRESS
        appe(lnkn,lnkk,"    ") : mk4(lnkn,lnkk-3,val("0x"+ke)) ' LINK NUMBER
        mk4(t,j,0) : j+=4
        goto nexw
      case 0x64 : 'GD' DATA SIDE LINK
        appe(lnkd,lnkj,"    ") : mk4(lnkd,lnkj-3,j) 'LINK LIST
        goto nexw
      end select
      '
      '
      'SEARCH BACKWARDS FOR LABEL
      '--------------------------
      '
      do
        b--
        if b<0
          exit do
        endif
        c=bk(b).n
        d=0
        if c=nsi
          d=1 'MATCH NAMESPACE REFERENCE
        endif
        if c=0
          d=1   'ACCEPT NULL NAMESPACE
        endif
        '
        if ke=bk(b).w and(d<>0)
          '
          n=bk(b).p-j 'ADDRESS DIFFERENCE
          '
          'LONG / QUAD ADDRESSES
          '
          if m=0x67 'GG'
            if cpuw=8
              m=0x71 'GQ'
            else
              m=0x61 'GA' sys 64 bit or 32 bit
            endif
          endif
          '
          select m
          case 0x61 'GA'
            mk4(t,j,n+j-1) : j+=4
            goto nexw ' A LONG OFFSET FROM 0 (32 BIT)
          case 0x71 'GQ'
            mk8(t,j,n+j-1) : j+=8
            goto nexw ' A QUAD OFFSET FROM 0 (64 BIT)
          case 0x6c 'GC'
            mk4(t,j,n-4) : j+=4
            goto nexw   ' L LONG RELATIVE
          end select
          '
          n--
          '
          'OTHERWISE SHORT JUMP RANGE
          '--------------------------
          '
          if (n<-128)or(n>127)
            ers=ke+" jump out of range (-128..+127) "+str(n)
            ert=2 : goto exitf ' short jump out of range
          endif
          '
          'SHORT JUMP
          '----------
          '
          mid(t,j)=chr(n and 255) : j++ : goto nexw
        endif
      loop
      '
      'NOT FOUND
      '
      '------------------
      'LOG AS FORWARD REF 'system 'q' 64 bit or 'a' 32 bit
      '==================
      '
      if m=0x67 'GG'
        if cpuw=8
          m=0x71 'GQ'
        else
          m=0x61 'GA
        endif
      endif
      '
      n=neb
      xn(xib)=ke
      xf(xib)=fnmks
      fwdref fwk at @fw(xib)
      'fwk.p    'POSITION CODE (NEGATIVE INDICATES LONG LINK)
      fwk.c=v   '2 LETTER ENCODING
      fwk.d=n   'DEPTH / NESTING LEVEL
      fwk.m=m   'LINKAGE MODE CODE
      fwk.n=nsi 'NAMESPACE CODE
      fwk.l=lln 'LINE NUMBER
      a=0
      if (m=0x6c)or(m=0x61)or(m=0x71)
        fwk.p=-j
        xib++
        j+=4 'RESERVE SPACE
        if m=0x71
          j+=4 'RESERVE EXTRA SPACE FOR QUAD
        endif
        exit do' g
      endif
      '
      fwk.p=j
      xib++ : j++ : exit do' g  'OTHERWISE SHORT
      '
    endif 'G INSTRUCTION
    '
    '
    '-----------
    'X EXIT NEST
    '===========
    '
    'LOG AS FWD REFERENCE
    '
    if a=0x78
      xn(xib)="" : n=neb
      if (m>48)and(m<58)
        n=neb+49-m : m=0x6c
      endif
      if n<0
        n=0
      endif
      int mi=xib
      fw(mi).d=n
      fw(mi).n=nsi
      if m=0x6c
        i++
        fw(mi).p=-j
        fw(mi).c=rbr
        xib++ : j+=4 : exit do' xl x2 x3 exit
      else
        fw(mi).p=j
        fw(mi).c=rbr
        xib++ : j++
        exit do' x exit
      endif
    endif
    '
    '
    '-------------
    'R REPEAT NEST
    '=============
    '
    if a=0x72 
      if m=0x6c
        i++ : v=nb(neb)-j-4 : mk4(t,j,v)
        j+=4 : exit do ' rl repeat
      endif
      v=nb(neb)-j-1
      if v<-128
        ers="'Repeat' out of range (-128..+127) "+str(v)
        ert=3 : goto exitf ' short loop out of range
      endif
      mid(t,j)=chr(v and 0xff) : j++
      exit do
    endif
    '
    '
    '--------------------
    'Z ZAP PREVIOUS LABEL
    '====================

    if a=0x7a
      'search backwards for the last matching label
      i++
      ke=aword(s,i)

      b=bke
      do
        b--
        if b<0
          exit do
        endif
        c=bk(b).n
        d=0
        if c=nsi
          d=1 'MATCH NAMESPACE REFERENCE
        endif
        if c=0
          d=1   'ACCEPT NULL NAMESPACE
        endif
        '
        if ke=bk(b).w and(d<>0)
          bk(b).n=-1 'SET UNREACHABLE NAMESPACE
          exit do
        endif
      loop
      exit do
    endif
    '
    '
    '======
    'VALUES
    '======
    '
    '
    'otherwise assume a decimal octal or hex code
    '
    '---------------------
    'H HEXADECIMAL NUMBERS
    '=====================
    '
    if a=0x68
      i+=2
      pt=strptr(t)
      qt=strptr(s)
      '
      '
      mov rcx,qt
      add rcx,i
      dec rcx 'offset
      rhgap:
        mov al,[rcx]
        inc rcx
        cmp al,0
        jz xhgap
        cmp al,32
        jle rhgap
      xhgap:
      dec rcx
      dec rcx 'align for hexaval
      mov rsi,pt
      add rsi,j
      dec rsi 'offset
      call hexaval
      mov cl,m
      '
      cmp cl,0x62 'hb' word
      jnz hexl2
      mov [rsi],al
      mov eax,1
      jmp xhexli
      '
      hexl2:
      cmp cl,0x77 'hw' word
      jnz hexl4
      mov [rsi],ax
      mov eax,2
      jmp xhexli
      '
      hexl4:
      cmp cl,0x6c 'hl' long
      jnz hexl8
      chexl4:
      mov [rsi],eax
      mov eax,4
      jmp xhexli
      '
      hexl8:
      cmp cl,0x71 'hq' quad
        jnz hexlg
        chexl8:
        mov [rsi],eax
        mov [rsi+4],edx
        mov eax,8
        jmp xhexli
        '
        hexlg:
        cmp cl,0x67 'hg' system (4 or 8 byte)
        jnz xhexli
        cmp dword cpuw,8
        jnz chexl4
        jmp chexl8
        '
        mov eax,0 'no interpretation
        '
        xhexli:
        '
        add j,eax
        '
      '
      skipspace(s,i)
      exit do
    endif
    '
    '
    '-----------------
    'N DECIMAL NUMBERS
    '=================
    '
    if a=0x6e
      i+=2
      pt=strptr(t)
      qt=strptr(s)
      '
        '
        mov rcx,qt
        add rcx,i
        dec rcx 'offset
        mov rsi,pt
        add rsi,j
        dec rsi 'offset
        rngap:
          mov al,[rcx]
          inc rcx
          cmp al,0
          jz xngap
          cmp al,32
          jle rngap
        xngap:
          dec ecx
          '
          call ascii_to_float rcx
          mov al,m
          '
          cmp al,0x77 'nw' word
          jnz numl4
          fistp word [rsi]
          mov eax,2
          jmp xnumli
          '
        numl4:
          cmp al,0x6c 'nl' long
          jnz numl8
          cnuml4:
          fistp dword [rsi]
          mov eax,4
          jmp xnumli
          '
        numl8:
          cmp al,0x71 'nq' quad
          jnz numlg
          cnuml8:
          fistp qword [rsi]
          mov eax,8
          jmp xnumli
          '
        numlg:
          cmp al,0x67 'ng' system (4 or 8 byte)
          jnz numl1
          cmp dword cpuw,8           
          jnz cnuml4
          jmp cnuml8
          '
        numl1:
          cmp al,0x62 'nb' byte
          jnz numfl4
          fistp word [rsi]
          mov eax,1
          jmp xnumli
          '
        numfl4:
          cmp al,0x73 's' single
          jnz numfl8
          fstp dword [rsi]
          mov eax,4
          jmp xnumli
          '
        numfl8:
          cmp al,0x64 'd' double
          jnz xnumli
          fstp qword [rsi]
          mov eax,8
          jmp xnumli
          '
        xnumli:
          '
          add j,eax
          '
        '
        '
        skipspace(s,i)
      exit do
    endif
    '
    '
    exit do ' always drop out
    '
  loop 'END CASES
  '
  '=====
  nexw:
  '=====
  '
  do ' find delimiting char before next word 
    if (i>l)or(bb(i)<=32)
      exit do
    endif
    i++
  loop
  '
  if xib>sizli
    ert=15 : goto exitf ' ref limit
  endif
  '
loop
'
'=====
exitf:
'=====
'
'
'LINK INITIALISED DATA TO CODE
'=============================
'
'first get offset of uninitialised data (bss)
'this value is stored in ebx therefore
'data is accessed as a negative offset from this position
'
'
'-------------------------------------------------
'HEADER | CODE | DATA | BSS | EDATA | IDATA | RSRC
'-------------------------------------------------
'
'
n=lnki-1
for m=1 to n step 4    'LIST OF DATA LINKS
  a=midval(lnkc,m)     'GET CODE PATCH LOCATION
  b=midval(lnkn,m)*4-3 'DATA INDEX
  c=midval(lnkd,b)-bss 'DATA LOCATION RELATIVE TO .bssdata
  mk4(t,a,c+4)         'PATCH DATA LOCATION INTO CODE (1st 4 bytes gives length)
next
'
'
'CHECK FOR ERRORS
'===============
'
if j<2
  ers="No code to generate" : ert=10
endif
if (ert=0)and(xib>0)
  ers="Linker found unidentified names:"
  v=0 : a=0
  '
  do
    if v>=xib
      exit do
    endif
    int mi=v
    a=fw(mi).c
    n=abs(fw(mi).n)
    wd=fw(mi).l+chr(9)
    if nsi
      wd+=mrcso(nsi,0)
    endif
    ers+=cr+wd+xn(v)+chr(9)+xf(v) '"level "+str(fw(mi).d)
    v++
  loop
  '
  ers+=cr
  ert=1000000+fw(xib-1).c 'unresolved refs
endif
'
if ert>0
  gbo=1
  return chr(0xc3)
else
  gbo=j-1
  return left(t,gbo)
endif
end function


