


'PROCEDURES USING INDIRECT RECURSION
====================================
'
! mword(string*s, int*i) as string
! pword(string*s, int*i) as string

! vars(string*s)
! tmpvar() as string
! NewTmpVar(string*ty) as string

! metaval( string*s, int*i, string*wa, int tp) as double

! express( string*s, int*i,*typx) as string
! arrayres(string*s, int*i, string*wr) as string
! procedures(string*s, int*i, string*wr) as string



'procedure linesltrim(string*s)
'==============================
'end procedure



function isptr(string*s, int *i) as int
=======================================
int d,q
do
  skiplspace(s,i)
  select ascn
  case 42
    i++ : d++ : continue do
  case 91
    if asc(s,i+1)=93
      i+=2 : q++ : continue do
    endif
  case 0x70
    if wordahead(s,i)="ptr"
      i=nwd : d++ : continue do
    endif
  end select
  exit do
loop
function=d+q
end function


'=====
'PARSE
'=====






'       #######
'      #       #
'      #       #
'              #
'             #
'       ######
'      #
'      #
'
'     ###
'     # #
'     ###

    '========
    'IDENTIFY
    '========





function isreg(string*wr) as int
================================
  '
  int a
  a=lookupm(wr)
  if a
    if drc(a).a=-10
      function=drc(a).c+1
    endif
  endif
end function

int typt 'typedef type
'
function identype(string*s) as int
==================================
  '
  int a,b,c,n,i=1
  static string w1,wm
  indt=0 'TYPE INDIRECTION ACCUMULATOR
  ary="" 'TYPE ARRAY ACCUM
  a=asc(right(s,1))
  if a=42 '*' POINTER
    a=ascn 'SAVE ASCN
    wm=tword(s,i)
    indt=isptr(s,i)
    ascn=a
  else
    wm=s
  endif
  '
  ridentype1:
  '----------
  '
  if wm=""
    exit function
  endif
  '
  typt=lookupm(wm)
  '
  if typt
    a=typt
  else
    return 0
  endif
  '
  ridentype2:
  '----------
  '
  b=drc(a).a
  '
  ridentype3:
  '----------
  '
  select b
    case -3 'TYPE / STRUCT / CLASS
      n=a+typh
      lent=drc(a).b
      if lent=0 'incomplete record
        lent=8
        return n
      endif
    case -8 'TYPEDEF REF
      n=drc(a).f
      lent=drc(a).b ' pointer (BSTR or BSTR byref)
      c=drc(a).d
      indt+=c 'INDIRECTION
      '
      w1=mrcso(a,2)
      if w1
        ary=w1+" "+ary 'ARRAY DATA
      endif
      b=drc(a).e 'METATYPEDEF
      if b=-5
        indt=0 : ary=""
        return cpuw 'FUNCTION POINTER TYPE AS SYS
      endif
      if n<typh
        return n
      else
        a=n-typh 'LOCATE BASETYPE OR TYPEDEF
        goto ridentype2
      endif
    case -15 'PRIMITIVE TYPES
      n=drc(a).f
      lent=n and 15 ' pointer (BSTR or BSTR byref)
      if lent=0 'void / cpu / fpu
        if cpuw=8
          lent=cpuw 'position maintainer 64bit params
        endif
        if indt
          lent=cpuw
          n=cpuw
        endif
      'elseif n=0x48
      '  if cpuw=8
      '    n=8 'sys instead of quad
      '  endif
      elseif idword(" sys any ",wm)  
        n=cpuw : lent=cpuw
      elseif (n>=0xa0)and(n<0x100)
        if n>=0xc0
          lent=cpuw
        elseif drc(a).d>0
          lent=cpuw 'POINTER
        endif
      endif
      return n
    case -16
      if wm="string"
        lent=cpuw : return 0xe1
      endif
      return 0
    case -22 'internal code storage
    case -21 to -18
      if nmac=0
        wm=mrcso(a,1) : goto ridentype1 'MACRO RESOLVE
      endif
      return 0
    case -33
      lent=cpuw : return cpuw 'ENUMERATION
    case else
      return 0
  end select
  '
  return n
  '
end function 'identype



procedure ctype(string*s, int*i, string*wr)
===========================================
  '
  'TRANSLATE C PRIMITIVES
  '
  '
  'arrays and pointers and functions resolved in o2prep.bas
  '
  int a,b,c,m,le,aa,ai,am
  string wn
  m=8
  wn=wr
  ai=i
  am=m
  skiplspace(s,i)
  do
    c=dic(" signed 1, unsigned 2, long 3, wide 4, short 5, char 6, wchar 7, string 8, ",wr)
    select c
    case 0 : 
      aa=lookupm(wr) : c=0
      if aa
        c=drc(aa).a
        if (c=-15)or(c=-8)or(c=-3)
          exit do 'INCLUDE TERM
        endif
      endif
      i=ai : wr=wn : exit do 'EXCLUDE TERM
    case 1 : b or= 1 : a=1
    case 2 : b or= 1 : a=2
    case 3 : am=m : b += 8  : m+=m
    case 4 : am=m : b += 8  : m+=m
    case 5 : am=m : b += 8
      if m>1 
        m\=2
      endif
    case 6 : b or= 2
      if a=1
        wr="sbyte"
      elseif a=2
        wr="ubyte"
      endif
    case 7 : b or= 2
      if a=1
        wr="short"
      elseif a=2
        wr="word"
      endif
    case 8 : exit do 'STRING
    end select
    '
    if isxn
      exit do
    endif
    wn=wr : ai=i
    wr=tword(s,i)
    if tyd
      if isxn
        wr=wn : i=ai : exit do 'tyd TYPEDEF FLAG
      endif
    endif
  loop
  skiplspace(s,i)
  '
  if b
    '
    if idword(" long short wide ",wr)
      m=am 'SUPPRESS FINAL SCALER
    endif
    '
    typ=identype(wr)
    if (typ>0)and(typ<0x100)
      le=lent
      if typ<0x40
        if a=1
          typ and=0xffffffdf 'SIGNED ADJUSTMENT
        elseif a=2
          typ or= 0x20 'UNSIGNED ADJUSTMENT
        endif
      endif
      if m<>8
        le=(typ and 15)*.125*m
        if typ<0x80
          lent=le 'LENGTH ADJUSTMENT 'not strings
        endif
        'long double=extended (10 bytes)
        if le=16
          if typ=0x68
            le=10 : lent=le
          endif
        endif
      endif
      typ=(typ and 0xffffffe0)+le 'REFORMULATE TYPE
      if cpuw=4
        if typ=8
          typ=0x48 'handled by fpu
        elseif typ=0x28
          typ=0x58 'handled by fpu
        endif
      endif
      wn=typename(typ) 'REDEFINE TYPE NAME
      if wn
        wr=wn
      else
        ers="Unable to resolve altered type: "+wr : ert=200
      endif
    endif
  endif
  '
end procedure


function subsas(string*s, int*i, string*ur, int igb) as int
===========================================================
  int a,j,k,b,c,d,e,f
  string wr,u
  b=i
  u=ur
  skiplspace(s,i)
  if isxn
    select ascn
    case 41,125,44 ' ) } ,
    case else
      goto nsubsloop
    end select
  endif
  do
    if igb
      nextinstruct(s,i) 'LINE INSENSITIVE WITH BRACKETS
    else
      skiplspace(s,i)
      if iss(ascn)
        exit do 'END OF STATEMENT EXIT
      endif
    endif
    if ascw=44
      i++ 'skip comma
    endif
    wr=tword(s,i)    'rbr or word
    e=lenw
    '
    if (ascw=41)or(ascw=125)
      exit do 'past end bracket
    endif
    d=0
    if ascn=61
      if asc(s,i+1)<>61 'exclude '=='
        d=1 'named param expr offered
      endif
    endif
    '
    if d=0 'params given in natural order
      i=swd
      f=instr(f+1,u,"=")
      if f 'default xpr available for substitution
        a=f+1 'skip '='
      else
        a=0 'fail to locate default
      endif
    else 'd=1  '
      a=0
      i++ 'SKIP '='
      do
        a=instr(a+1,u,wr)
        if a=0
          exit do 'fail
        endif
        if asc(u,a-1)<=44
          a+=e
          skiplspace(u,a)
          if ascn=61 '='
            a++ 'skip '='
            exit do 'located
          endif
        endif
      loop
    endif
    if a
      wr=captsx(s,i) 'capture expression
      e=len(wr)
      k=a
      capts(u,a) 'expression to excise
      if e
        'REPLACE THE DEFAULT
        u=left(u,k-1)+wr+mid(u,a)
        a=k+e
      endif
      f=a
    else 'a=0 fail
      i=b
      exit function 'a failed substitution
    endif
    skiplspace(s,i)
    if ascn=44
      i++ : continue do 'next oaram xpr to process
    endif
    'otherwise assume end of params
    if igb
      nextinstruct(s,i)
      i++ : skiplspace(s,i) 'skip right bracket
      if ascn=61 '='
        'extra param?
        if asc(s,i+1)=61 'exclude '=='
          '
        else
          i++ : skiplspace(s,i)
          igb=0
          continue do ')=var
        endif
      endif
    endif 'igb
    exit do
  loop
  '
  nsubsloop:
  '
  'stripas:
  =========
  ' (,a=3,b=4,) becomes (   3,  4 )
  a=2
  do
    j=a
    wr=tword(u,a)
    if lenw=0
      exit do
    endif
    if ascw=44
      if (ascn=rbr)or(ascn=125)
        exit do
      endif
      j=a
      wr=tword(u,a)
      if ascn=44
        a=0
        exit do 'UNDEFINED VAR
      elseif ascn=61
        a++
        if mid(u,a,2)=".,"
          a=0
          exit do 'UNDEFINED MEMBER
        endif
        midspace(u,j,a) 'BLANK OUT X=
        capts(u,a) 'STRIDE STATEMENT
      endif
    endif
  loop
  if a
    e=len(u)-1
    mid(u,2)=" "
    mid(u,e)=" "
    inserts(s,u,i)  'INSERT RESULTING PARAM LIST
    skipspace(s,i) 'SKIP TO OPENING BRACKET
    return 1 'FLAG SUCCESS
  else
    i=b  'PARAM ERROR
  endif
  end function


function HiMac(int mm, string*s, int*i) as string
=================================================
  int a,b,c,m,n,md,igb,itm
  string w1,w2,w3,w4,w5,w6,wa,wt,wv
  '
  md=drc(mm).f    ' MODE 104 #DEFINE, MODE 109 MACRO
  w1=mrcso(mm,1)  ' BODY
  w3=mrcso(mm,3)  ' PROTOTYPE EXCLUDING OUTER BRACKETS
  '
  if incli
    function=w1
    capts(s,i) 'skip params
    jmp fwd xhimac
  endif
  '
  'PARAMETERS BRACKETS ?
  '
  skiplspace(s,i)
  if ascn=lbr
    i++
    skiplspace(s,i)
    igb=1
  endif
  '
  if w3=""
    goto nhimac 'NO PARAMS TO REPLACE
  endif
  '
  'EXPLICIT TYPE OF MACRO
  '
  '
  if drc(mm).d
    wt=mrcso(mm,2)  ' RETURNTYPE
    w2=newtmpname()
    if nisxn
      w2+=cm
    endif
    inserts(s,w2,i)
  endif
  '
  b=1
  if md=109 
    n=0x1c ' hash and dot boundary / instr
  else
    n=0x08 ' hash boundary
  endif
  do 'MAKE UNIQUE SYMBOLS
    icas=1
    w4=tword(w3,b)
    m=swd
    select ascw
    case 0     : exit do
    case 35    : continue do '#REST
    case 44,58 : continue do ','  ':'
    case 61
      capts(w3,b) 'default expression
      continue do
    end select
    tmpi++ : w5=c127+w4+str(tmpi)
    replacewd(w1,w4,w5,n)
    w3=left(w3,m-1)+w5+mid(w3,b)
    b=m+len(w5)
  loop
  '
  b=1
  c=0
  do 'MAIN LOOP
    icas=1
    w4=tword(w3,b) 'NEXT PARAM FROM PROTOTYPE
    '
    if ascn=61 '=' DEFAULT VALUE
      b+=1
      w5=captsx(w3,b)
    else
      w5=""
    endif
    '
    if lenw=0
      exit do 'NO FURTHER PARAMS
    endif
    if ascn=44
      b++  'SKIP COMMA IN PROTOTYPE
    endif
    '
    if igb
      nextinstruct(s,i) 'SUPPORT MULTILINE
    else
      skiplspace(s,i)
    endif
    '
    m=1 'REPLACEMENT FLAG
    '
    if isxn 'NO MORE PARAMS GIVEN
      '
      'USE DEFAULT VALUE
      if w5
        w2=w5
      else
        m=0 'NO REPLACEMENT
      endif
      jmp fwd replacew
    endif
    '
    'OTHERWISE MAKE SUBSTITUTION FROM PARAM
    '
    a=1
    if w4="#rest"
      noco=1
    endif
    'CAPTURE SINGLE WORD OR EXPRESSION
    w2=captsx(s,i)
    noco=0
    '
    if ascn=44
      i++ : nextinstruct(s,i)
    endif
    '
    =========
    replacew:
    =========
    '
    if m 'w2<>w4
      if md=109 'MACRO
        n=0x06 'IGNORE QUOTES BUT ## AND DOT BOUNDARIES
      else 'md=104 #DEFINE
        n=0x01 '## AND #
      endif
      '
      'REPLACE W4 WITH W2 IN BODY W1
      replacewd(w1,w4,w2,n)
    endif
    '
    itm++
    c++
    if itm=1 'FIRST TERM
      if drc(mm).d
        wv=w2
        if typr
          w2=tword(wt,1)
          if w2="any"
            wt=typename(typr)
            if ascn=42
              wt+="*"
            endif
          endif 'any
        endif 'typr
        vars(wt+" "+wv) 'CREATE RETURN VAR
      endif 'wt
    endif 'c=1
    '
    '=========
    'nmactype:
    '=========
    '
  loop
  '
  =======
  nhimac:
  =======
  '
  if drc(mm).d
    hiex+=w1+cr
    function=wv
    rps=8 'MACRO FUNCTION
  else
    function=w1
  endif
  if igb
    nextinstruct(s,i)
    if ascn=rbr
      i++ 'closing bracket
    else
      ers="Too many params for macro " mrcso(mm,0)
      ert=361
    endif
  endif
  if (igb=0)or(asc(s,i)<33)
    if function 
      function+=" "
    endif
  endif
  skiplspace(s,i)
  if isc(ascn)
    endline(s,i) 'skip comments
  endif
  '
  xhimac:
  =======
  incli=0
end function 'himac





procedure readvals(string *wm, int *k)
======================================
  '
  int a,c,m,n,v
  string w1
  '
  n=ascn
  '
  a=readint(wm,k)          'LENGTH OF MEMBER ELEMENT
  woff=readint(wm,k)       'OFFSET
  plq=k                    'PATCH POSITION FOR PROCLIST POSITION
  pls=zword(wm,k)          'PROCLIST POSITION
  varf=readint(wm,k)       'ELEMENT VAR/PROC/METHOD
  cco=asc(wm,k)-65  : k++  'CALLING-CONVENTION
  if cpuw=4
    crgd=cco and 0x60      'THISCALL FASTCALL
  endif
  cco=cco and 0x1f
  vtq=asc(wm,k)-65  : k++ 'VIRTUAL MODALITY
  prfs=asc(wm,k)-65 : k++ 'PUBLIC 0 PRIVATE 1
  k++
  'PARAMS SIGNATURE
  ascn=asc(wm,k)
  if ascn=44
    sig="" : k++
  else
    sig=zword(wm,k)
  endif
  '
  '
  'RETURN SIGNATURE (AND TYPE)
  '
  sog=zword(wm,k)
  '
  'TYPE GIVEN BY REF-NUMBER, PRIM-CODE OR NAME
  '
  int ta=asc(sog)
  if isn(ta) 'number indicates higher type
    typ=val(sog)
    sog=typename(typ)
    a=typ-typh 'location
    lent=drc(a).b
  else
    typ=identype(sog) 'also sets lent
  endif
  elsize=lent
  lent=a
  '
  '
  'ARRAY SIZE
  '
  if ascn=91
    capture(wm,m,k,0)
    m++
    aml=val(mid(wm,m,k-m)) 'LITERAL
  else
    aml=1
  endif
  '
  'DEFAULT PARAM VALUES (,a=3,b=4,)
  '
  if ascn=lbr
    capture(wm,m,k,a)
    dvm=mid(wm,m,k-m)
  endif
  '
  ascn=n
  '
end procedure 'readvals


procedure splitoperand(string*wr)
=================================
  int a
  a=instrevn(-1,wr,cr)
  if a
    a+=2
    wpfx+=left(wr,a-1)
    wr=mid(wr,a)
  endif
end procedure


function nextmembname(string*wm, int*k) as string
=================================================
  '
  'GET NEXT ELEMENT IN STRUCTURE, EXCLUDING METHODS
  '
  int a
  string w1
  typ=0
  if k<=0
    k=1
    a=instr(k,wm,sectmk)
    if a
      k=a+6
    endif
  endif
  do
    k=instr(k,wm,rmk)
    if k=0
      exit do
    endif
    k++
    w1=wordahead(wm,k)
    if right(w1,3)="___"
      continue do 'SKIP '___' names (pvft etc)
    endif
    k=nwd
    'READ ATTRIBUTES
    '
    readvals(wm,k)
    if (varf=5)or(prfs>0)
      continue do 'IGNORE GROUP HEADER RECORD
    endif
    exit do
  loop
  if (varf=3)or(varf>=8)
    typ=cpuw 'TREAT AS POINTERS
  endif
  prfs=0
  return w1
end function

procedure gettoff(int mt)
=========================
  int a,c
  toff=0
  c=lookupm(mrcso(mt,0)+"_table")
  'itr potentially lost namespace
  'c=drc(mt).c '_table index
  '
  if c
    regst=mid(mrcso(c,1),2,3)
    toff=drc(c).c 'TABLE BASE OFFSET USED LATER
  else
    regst=""
  endif
end procedure


function nextproc(int q, string*wr, int*lb) as int
==================================================
  '
  'FOR FUNCTIONS
  '
  string s=mrcso(q,1)
  int m
  int k=1
  lb=0
  sig=yword(s,k)             'PROTOTYPE SIGNATURE
  sog=yword(s,k)             'RETURN TYPE OR COMMA
  wr=yword(s,k)              'FUNCTION SIGNAME / ALIAS / VECTOR / OFFSET
  '
  'FURTHER OPTIONAL DATA
  '
  if ascn>=48
    lb=readint(s,k)          'LIBRARY LIST NUMBER
    mtyp=asc(s,k)-65         'METATYPE
    cco=asc(s,k+1)-65        'CALLING CONVENTION
    if cpuw=4
      crgd=cco and 0x60        'THISCALL FASTCALL
    endif
    cco=cco and 0x1f
    k+=3 : ascn=asc(s,k)
  else
    mtyp=16 : cco=0          'CORE FUNCTION
    if cpuw=8
      cco=2     'MS64
    endif
  endif
  '
  if ascn>47
    pls=yword(s,k)           'LIST OFFSET FOR PROCLIST ENTRY
  endif
  if ascn=40
    capture(s,m,k,0)
    dvm=mid(s,m,k-m)         'DEFAULT PARAM VALUES
  endif
  varf=8
  typ=identype(sog)
  function=lookupr(q)
end function


procedure indiri(string*wr, int n)
==================================
if n
  wpfx+=medi+wr+cr
  n--
  if n
    wpfx+=repeats(medi+pedi+cr,n)
  endif
endif
end procedure
'

procedure findmember(string*wki,*wr, int*ki)
============================================
  '
  'RESOLVES MEMBERS
  'params:
  'wki member to find
  'wr  operand output
  'ki  record index and result
  '
  int a,b,c,ch,n,v,k,chmp,ml,mt,mcc,clss
  string wm,wn,ws,w1,wk
  'locals
  'wm  type record to search
  'wn  operand coded name
  'w1  temp string
  'wk  member to look for
  wk=wki
  if asc(wk)=34
    wk=mid(wk,2,len(wk)-2)
  endif
  ml=mp 'current record index
  '
  'IS IT A VARIABLE?
  '=================
  '
  mt=drc(ml).a
  if mt>=typh
    mt-=typh 'type index
  endif
  '
  'STRUCTURE INDEX
  '
  if mt>=0
    '
    ind=drc(ml).d and 255 'INDIRECTION
    voff=drc(ml).c        'BASE OFFSET OF VARIABLE
    '
    wbse=mrcso(ml,1)
    splitoperand(wbse) 'adds to wpfx
    '
    if (ind=0)and(wpfx="")
      if asc(wbse,2)=35
        a=len(wbse)-2 '[#name]
      else
        a=3
      endif
      wn=mid(wbse,2,a)
    else
      wn=qedi
      indiri(wbse,ind) 'CREATE INDIRECTION CODE
    endif
    '
  else 'mt<0 NOT A VAR
    '
    mcc=mt
    mt=ml
    ind=0
    voff=0
    if drc(ml).d>=8 'atx
      ers="Not possible with extern pure/com: "+ow : ert=601 : exit procedure
    endif
    '
  endif
  '
  '
  clss=mt 'class index
  k=ki   'member location offset
  '
  '-------------------------------------------------
  rmatchm:  'RECURSION POINT FOR INDIRECT STRUCTURES
  '-------------------------------------------------
  '
  'GET STRUCTURE
  '-------------
  prfs=0
  mq=mt
  wm=mrcso(mt,1) 'STRUCTURE RECORD
  '
  '
  'CHECK ELEMENT EXISTS
  '--------------------
  '
  'element with attached signature
  'addreses of methods etc
  a=instr(wk,"#")
  'method search
  if (a>0)or(mcc=-3)
    if a>0
      'split name
      w1=mid(wk,a) 'signature
      wk=left(wk,a-1) 'name without signature
      c=0
    else
      w1="" 'no signature
      c=1
    endif
    b=len(wk)
    '
    'signature matching
    ws=rmk+wk+" "
    do
      'search backwards
      a=instrevn(k,wm,ws)
      if a
        k=a+b+2
        readvals(wm,k)
        if prfs>0 'check whether private or protected
          if prfs=1
            clss=mt 'protected
          endif
          if clsi<>mq or clss<>mt
            k=a-1
            continue do 'continue search
          endif
        endif
        'check matching sinature
        if (c=1)or(w1=splitsig(sig))
          ki=a : goto methodev
        else
          k=a-1
        endif
      else
        exit do
      endif
    loop 'signature matching
  else 'normal search
    a=instrevn(k,wm,rmk+wk+" ") : chmp=0
  endif

  if a=0
    '
    'CHECK FOR INDIRECT STRUCTURE
    '----------------------------
    '
    'LOOK FOR DOTTED PART OF NAME
    '
    a=instr(wk,"->")
    b=instr(wk,".") 'look for first dot
    '
    if a+b
      if b=0 
        b=a
      elseif a=0
        '
      elseif a<b
        b=a
      endif
    endif
    '
    if b
      w1=left(wk,b-1)
      if a=b
        b++ '->' ARROW cpointer
        'itr check use with indirect members
      endif
      '
      'REVERSE-SEARCH FOR ROOT NAME
      a=instrevn(k,wm,rmk+w1+" ")
      '
      if a=0
        ki=0
        exit procedure 'NOT LOCATED
      endif
      '
      wk=mid(wk,b+1) 'CHOMP WK
      b=len(w1) 'first part of name located
      chmp=1
      '
    else 'no dot
      '
      ki=0
      exit procedure 'NOT LOCATED
      '
    endif
  else 'main name located
    b=len(wk)
  endif
  '
  '
  =========
  readattr:
  =========
  '
  ki=a
  k=a+b+2 'skip over identified name
  readvals(wm,k)
  'check whether private or protected
  if prfs>0
    if prfs=1
      clss=mt 'protected
    endif
    if clsi<>mq or clss<>mt
      'continue search for root word
      k=a-1
      a=instrevn(k,wm,rmk+w1+" ")
      if a=0
        ki=0
        exit procedure 'NOT LOCATED
      endif
      goto readattr
    endif
  endif
  '
  '
  =========
  methodev:
  =========
  '
  v=0
  '
  if varf
    '
    'CHECK FOR CLASS STATIC ELEMENTS AND METHODS
    '-------------------------------------------
    '
    'VARF CODES
    '
    '1   body member
    '3   pointer body member
    '5   body group header
    '8   procedure pointer
    '9   method pointer
    '10+ inherited method pointer
    '
    '
    if (varf<9)or(mcc=-3)
      v=woff 'STRUCTURE OFFSET
    endif
    '
    '
    'METHODS
    '-------
    '
    if varf>8
      gettoff(mt)
      if mcc=-3
        wn=regst : voff=toff 'USE TABLE BASE FOR METHODS
      endif
    endif
    '
  endif ' VARF
  '
  '
  if (ind=0)and(len(wpfx)=0)
    v+=voff 'ADD VARIABLE BASE IF VF TABLE IS USED
  endif
  '
  'REBUILD THE ADDRESS OPERAND
  '===========================
  '
  ch=asc(wn)
  '
  if (v<>0)or(ch=35)
    '
    'RESOLVE HOST ADDRESS WITH OFFSET
    '
    if ch=35
      'resolve to abs address
      sys p=getvarptr(wn)
      if p=0
        ert=300 : ers="Host variable not found: "+wn
      endif
      wn=str(p+v) : v=0
    '
    'ADJUST ABSOLUTE ADDRESS OFFSET
    '
    elseif isn(ch)
      '
      'QUICK HEXADECIMAL CHECK
      '
      n=asc(wn,2)
      wn=str(val(wn)+v) : v=0
    endif
    '
  endif
  '
  wr=memreg(wn,v) 'COMPOSE OPERAND
  '
  '
  'CHECK IF INDIRECT STRUCTURE POINTER
  '===================================
  '
  if varf=3
    if wk
      '
      'IF FURTHER RESOLUTION REQUIRED
      '
      indiri(wr,1) 'appends to wpfx
      ind++
      '
      if chmp=0
        wr=pedi
        exit procedure 'RESOLVED
      endif
      '
      wn=qedi
      mt=typ-typh 'LOCATION OF NEW TYPE
      ind=0
      voff=0
      toff=0
      k=-1 'redo whole search
      goto rmatchm 'LOOP RECURSE FOR NEXT STRUCTURE
    endif
  endif 'varf=3
  if chmp
    ki=0 'NOT RESOLVED
  endif
  '
end procedure 'findmember


function identopeq(string*s, int*i, string*w1) as int
=====================================================
  if ascw=60 '<=
    exit function
  elseif ascw=61 '= ==
    'default to simple assign
    function=2
    w1="mov "
    if cnd
      'conditional expression
      function=0x14
      if asc(s,swd+1)=61
        i++ : skiplspace(s,i)
      endif
    endif
    exit function
  endif
  '
  op=identop(s,swd,i)
  w1=mid(s,swd,i-swd)
  skiplspace(s,i)
  i++
  skiplspace(s,i)
  '
  if (op=0)or(op>=typh)
    function=op
    exit function
  endif
  '
  ascw=61
  select op
  case 43 : w1="add " : function=8  '+=
  case 45 : w1="sub " : function=9  '-=
  case 42 : w1="mul " : function=14 '*=
  case 47 : w1="div " : function=15 '/=
  case 92 : w1="div " : function=15 '\=
  case 33 : w1="and " : function=65 'AND=    
  case 34 : w1="or "  : function=66 'OR=
  case 35 : w1="xor " : function=67 'XOR=
  case 71 : w1="&&"   : function=71 '&&=
  case 72 : w1="||"   : function=72 '||=
  case 73 : w1="^^"   : function=73 '^^=
  case else
    op=0
  end select
end function




function attributes(string s, int *i) as string
===============================================
  '-11
  int kn,a,c,k,m,wa,nl
  string wr,w1
  '
  kn=drc(mp).e 'attriute code
  '
  if ascn=lbr
    c=1 : i++ 'SKIP LEFT BRACKET
  endif
  '
  if nisxn
    if kn>30 'literal symbol attributes
      wr=tword(s,i)
      select kn
      case 31 'lpartof
        if dtf
          wr=left(wr,dtf-1)
        endif
      case 32 'rpartof
        if dtf
          wr=mid(wr,dtf)
        endif
      case 33 'vtypeof
        a=ascn
        wr=mword(wr,1)
        wr=typename(typ)
        ascn=a
      end select
      if c
        if ascn=rbr
          i++ : skiplspace(s,i) 'BLANK RIGHT BRACKET
        endif
      endif
      wr=tword(wr,1) 'sets state vars
      goto attrix
    endif
    '
    if kn<>21 'not strptr
      nmac=1
    endif
    w1=pword(s,i)
    '
    if isb(ascn)
      if (mc=-4)or(mc=-5)
        int odts=dts, orps=rps
        string ohiex=hiex
        wr=procedures(s,i,wr) 'supports polymorphs
        dts=odts : rps=orps : hiex=ohiex
      else
        capture(s,0,i,0)
      endif
      skiplspace(s,i)
    endif
  else 'no word given  isxn
    mp=0 : mc=0 'resolve
  endif
  nmac=0
  '
  if c
    if ascn=rbr
      i++ : 'SKIP RIGHT BRACKET ONLY
      'skiplspace(s,i)
    endif
  endif
  '
  '
  '
  wr="0" : k=mp : m=k
  '
  'VARIABLE OR STRUCTURE ?
  '
  if mc>=0
    m=mc
  endif
  '
  '
  '
  select kn
  '
  case 1 'SIZEOF
    '
    if mc=0
      if isq(ascw)
        wa=cpuw
        goto attrin
      endif
    endif
    if mp=0
      wa=elsz 'LAST MULTIASSIGN
    elseif mc>=0
      if varf
        wa=elsize
      else
        wa=lent
      endif
      if drc(mp).e>0
        wa=cpuw 'INDIRECT TYPE
      endif
    elseif idword(" string wstring bstring wbstring ",w1)
      wa=cpuw
    elseif idword(" char zstring asciiz ",w1)
      wa=1
    elseif idword(" wchar wzstring ",w1)
      wa=2
    elseif mc<0
      a=identype(w1)
      if a
        wa=lent
      endif
    endif
    goto attrin
    '
  case 2 'OFFSETOF
    '
    if mc>=0
      wa=drc(mp).c+woff
    endif
    goto attrin
    '
  case 3 'COUNTOF 'SPANOF NUMBER OF ELEMENTS OF MAIN ARRAY
    '
    if mp=0
      wa=elct+1 'LAST DATA SET ELEMENT COUNT
    else
      if elsize
        wa=aml
      else
        'static array
        wa=val(mrcso(mp,2))
      endif
      if wa=0
        wa=1 'not an array
      endif
    endif
    goto attrin
    '
  case 4 'BYTESOF: NUMBER OF BYTES OF MAIN ARRAY
    '
    if mp=0
      wa=(elct+1)*elsz 'LAST DATA SET ELEMENT COUNT
    else
      if elsize
        a=elsize
      else
        a=lent
      endif
      if drc(mp).e>0
        a=cpuw
      endif
      if elsize
        wa=aml*a
      else
        wa=val(mrcso(mp,2))*a
        if wa=0 
          wa=lent 'not an array
        endif
      endif
    endif
    goto attrin
    '
  case 5 'TYPEOF
    '
    nl=newline
    if mc>=0
      if sog
        wr=sog
      else
        wr=identypes(typ)
      endif
    elseif (mc=-4)or(mc=-5)
      wr=sog
    elseif mc=-31
      wr=sog
    elseif mc=-32
      wr="string" 'not bstring
    elseif mc<0
      wr=str(mc)+" "+_
     dicsn(metatypes,mc) 'TYPEOF TYPE
    endif
    '
  case 6 'STRUCTUREOF ENCODINGOF
    '
    wr=mrcso(m,1)
    '
  case 7 'PROTOTYPEOF
    '
    wr=mrcso(k,3)
    '
  case 8 'TYPECODEOF
    '
    wa=typ
    if varf>=8
      wa=-5
    endif
    if wa=0
      if mc
        wa=mc
      endif
    endif
    goto attrin
    '
  case 9 'RECORDOF
    '
    wr=writestates(k,k)
    '
  case 10 'WIDTHOF
    '
    wa=typ and 15
    goto attrin
    '
  case 11 'PTRLEVELOF
    '
    if (mc>=0)or(mc=-8)
      wa=drc(mp).d
      if varf
        wa=0
        if varf=3
          wa=1
        endif
      endif
    endif
    goto attrin
    '
  case 12 'METATYPEOF
    '
    nl=newline
    if mc>0
      wr="variable"
      if sog
        wr=sog
      else
        wr=identypes(typ)
      endif
    elseif mc<0
      wr=str(mc)+" "+_
     dicsn(metatypes,mc) 'TYPEOF TYPE
    endif
    '
  case 13 'FLAGSOF
    '
    wa=0
    if mp
      wa=drc(mp).h
    endif
    goto attrin
    '
  case 21 'STRPTR
    '
    makestrptr(w1)
    typ=cpuw
    'keep wpfx
    mc=0 : mp=0 : varf=0
    return w1
    '
  end select
  '
  '
  '------
  attris:
  '------
  '
  if nl
    if c=0
      wr=wr+" "
    endif
    typ=0 'raw code
  else
    wr=qu+wr+qu+" " 'quoted string literal
    typ=0xc1
  endif
  '
  goto attrix
  '
  '------
  attrin:
  '------
  '
  wr=str(wa)+" " : typ=cpuw
  '
  '------
  attrix:
  '------
  '
  wpfx=""
  mc=0 : mp=0 : varf=0
  return wr
  '
end function 'attributes






' #######   ######  ######
'  #     #  #       #
'  #     #  ####    ####
'  #     #  #       #
' #######   ######  #

function lomac(int p, string*s, int*i) as string
================================================
  int a,b,c,d,g,m,n,v,rc,lk
  string w1,w2,wk
  string wr,ws,wt
  '
  wk=mrcso(p,1)
  if wk=""
    exit function
  endif
  '
  '---------------
  'LOW LEVEL MACRO
  '===============
  '
  'CHECK NO SUBSTITUTIONS
  '
  if incli
    jmp fwd nmacres
  endif
  '
  'FIND HIGHEST PARAMETER
  '
  a=1 : b=48
  'get max count
  do
    a=instr(a,wk,"%")
    if a=0
      exit do
    endif
    a++
    v=asc(wk,a)
    if v=48 '%0
      'unique symbol substitution
      a++
      icas=1 'inhibit case conversion
      wr=tword(wk,a+0) 'a val not changed
      ws=mid(wk,swd)
      tmpi++ : wt=c127+wr+str(tmpi)
      replacewd(ws,wr,wt,4)
      wk=left(wk,a-3)+ws
    elseif v=33 '%!
      a++
      v=asc(wk,a)
    endif
    if (v>b)and(v<58)
      b=v 'UP TO 9 PARAMS
    endif
  loop
  '
  b=b-48
  a=1   'start at 1
  '
  'GRAB MACRO PARAMETERS
  '
  do
    if b<=0
      exit do
    endif
    skiplspace(s,i)
    g=0
    '
    'CAPTURE CONTENT BETWEEN BRACKETS
    'ARRAYS AND FUNCTIONS MUST BE CONTAINED INSIDE BRACKETS (..)
    '
    if ise(ascn)
      w1=""
    elseif isb(ascn)
      c=i
      capturi(s,m,c,i)
      if asc(s,i)>32
        g=1
      endif
      w1=mid(s,m,c)
    else
      'CAPTURE INDIVIDUAL WORD / NUMBER
      'ENSURE CAPTURE NEGATIVE NUMBER
      icas=1
      w1=tword(s,i)
      if ascw=45
        c=asc(s,swd+1)
        if isn(c)
          icas=1
          w1+=tword(s,i)
        endif
      endif
    endif
    '
    wp(a)=w1
    a++
    b--
  loop
  '
  a=1
  '
  'SUBSTITUTE WORD SYMBOLS AND MARKUP BLOCK SYMBOLS
  '
  do
    a=instr(a,wk,"%") 'ASCII 37
    if a=0
      exit do
    endif
    a++
    b=asc(wk,a)
    if b=33 '%!
      'REMOVE '!' WHEN NUMBER %!1..9
      wk=left(wk,a-1)+mid(wk,a+1)
      rc=1
      b=asc(wk,a)
    endif
    if (b>=48)and(b<=57)
      b-=48
      w2=wp(b)
      if rc '%!
        clcase(w2)
        lk=lookupm(w2)
        if lk
          if drc(lk).a=-18
            w2=mrcso(lk,1) 'RESOLVE DEF PARAM 
          endif
        endif
        rc=0
      endif
      c=len(w2)
      wk=left(wk,a-2)+w2+mid(wk,a+1)
      a+=c
    else
      a++
    endif
  loop
  '
  nmacres:
  ========
  '
  incli=0
  if not g
    if wk
      wk+=" "
    endif
  endif
  return wk
end function


function readline(string*s, int*i) as string
============================================
int b=i
endline(s,i)
if ascn=13
  i+=2
endif
return mid(s,b,i-b)
end function


/*
function mendline(string*s) as string
=====================================
int a,b,e,cn,thn,enf,stt,bg
int i=1
int j=1
stt=1
string w1,w2,wc
string u=nuls(ls*4)
do
  b=i
  w1=yword(s,i)
  if ise(ascn)
    e=1
    if isc(ascn)
      a=i : (endline(s,i)
      wc=mid(s,a,i-a)
      e=2
    endif
  endif
  if w1="if"
    cn=swd
    w2=mids,(s,b,i-b)
    if stt=0 'COMMENT AND NEWLINE
      cn=bg+1
      w2=wc+cr+space(cn-1)+w1
    endif
  elseif w1="then"
    thn=b
    w2=cr+space(cn+1)
    if e=0
      enf=1 'TO INSERT ENDIF
    else
      w2="" 'JUST OMIT THEN
    endif
  elseif (w1="else")and(cn>0)
    els=b
    w2=cr+space(cn-1)+"else"+cr+space(cn+1)
  else
    bg=swd
    stt=0    
    w2=mid(s,b,i-b)
  endif
  '
  mid(u,j)=w2
  j+=len(w2)
  '
  if ise(ascn)
    exit do
  endif
  '
  if e
    exit do
  endif
loop
if wc
  mid(u,j,wc)
  j+=len(wc)
endif
if enf
  mid(u,j)=cr+space(cn-1)+"endif"+cr
  j+=7
endif
return left(u,j-1)
end function



function mendif(string*s) as string
===================================
strin w1,w2
int a,e
int i=1
int j=1
string u=nuls(ls*2)
do
  w1=readline(s,i)
  if ascn=0
    e=1
  endif
  w2=mendline(w1)
  mid(u,j)=w2
  j+=len(w2)
  if e
    exit do
  endif
loop
return left(u,j-1)
end function
*/




function ResolveAsm(string*s, int*i) as string
==============================================
  int a,b,c,m
  string wk,wm,wn,wr,w1
  m=swd
  a=instr(m,s,"]")
  if a>m
    i=a+1
    '
    if i=swd+2
      goto sqbrw 'EMPTY []
    endif
    '
    wk=mid(s,m+1,a-m-1)
    '
    w1=tword(wk,1)
    '
    if ascw=35
      sys p=getvarptr(w1)
      if p
        w1="["+str(p)+"]" : 'HOST VARIABLE
        skiplspace(s,i)
        ascw=91
      else
        ers="host variable not found" : ert="4002"
      endif
      return w1
    else
      '
      'RESOLVE VARIABLE FB SYNTAX [VAR]
      '
      if dtf
        a=dtf-1
      else
        a=lenw 
      endif
      a=lookupm(left(w1,a))
      if a
        c=drc(a).a
        if (c>=0)or(c=-14) 'allow [function] or [method]
          ascw=asc(w1) : return w1
        endif
      endif
    endif
    '
    'OTHERWISE ASSUME A NORMAL ASM MEMORY OPERAND
    '
  endif
  '
  'RETURN WHOLE [..] ASM MEMORY OPERAND
  '
  sqbrw:
  '
  swd=m : wr=mid(s,swd,i-swd) : ascw=asc(wr) : skiplspace(s,i)
  '
  return wr
end function



int prv

function identwr(string*wr,*wk) as int
'=====================================
  '
  int a,b,c,d,m,mm,nth
  string w1
  '
  'CHECK FOR DOTTED NAMES
  '
  ridentwr:
  =========
  '
  if dtf
    ow=wr             'make it original (after macro resolution)
    d=asc(wr,dtf+1)
    if d=62 '.>
      a=2
    else
      a=1
    endif
    wk=mid(wr,dtf+a)  'possible member
    wr=left(wr,dtf-1) 'possible name
    if wr="that"
      wr=wk
      dtf=instr(wr,".")
      nth=1
      ow=wr
    endif
  endif
  '
  mm=lookupm(wr)
  '
  if mm
    if prv
      mm=lookupr(mm) 'PRIOR
      prv=0
      if not mm
        return 0
      endif
    endif
    '
    if dtf
      if drc(mm).a=-18 'a macro prefix
        wr=rtrim(mrcso(mm,1))+wk
        wr=tword(wr,1) 'new dtf etc
        ow=wr
        goto ridentwr
      endif
    endif
  else 'not mm
    if ascw=46
      wr=ow
      'not found nfnd ...
      goto nlookupmm    endif
  endif 'mm
  '
  if nth
    goto nlookupmm 'That' override
  endif
  '
  '
  'GIVE PRIORITY TO IMPLICIT `THIS` SYMBOLS IN METHODS
  '---------------------------------------------------
  '
  'CORE SYMBOLS ALWAYS HAVE PRIORITY (MESB)
  'BUT REGISTER-LIKE NAMES CAN BE USED
  '
  if ths
    if mm=0
      b=ths
    elseif mm<mesb
      '
      ''check for register-like names eg ax bx cx
      '
      if drc(mm).a=-10
        w1=wr : m=drc(ths).a-typh
        c=instrevn(-1,mrcso(m,1),rmk+w1+" ")
        if c 
          wk=w1 : dtf=5 : function=ths : exit function
        endif
      endif
    elseif mm<mest
      b=ths
    elseif wr="this"
      function=ths : exit function 'EXPLICIT THIS
    endif
  endif
  '
  if b
    '
    'CHECK FOR IMPLICIT THIS.
    '------------------------
    '
    m=drc(ths).a-typh
    c=0
    '
    if dtf
      w1=wr+"."+wk
      c=instrevn(-1,mrcso(m,1),rmk+w1+" ")
    else
      w1=wr
    endif
    '
    '
    '
    if c=0
      c=instrevn(-1,mrcso(m,1),rmk+wr+" ") 'either non-dotted or possibly indirect
    endif
    '
    if c
      wk=w1
      dtf=5 'IMPLICIT THIS
      ow="this."+ow
      function=ths
      exit function
    endif
    '
  endif
  '
  nlookupmm:
  '
  function=mm
  '
end function



macro dataset()
===============
  w1=newTmpName()
  w2=""
  if wordahead(s,i+1)="}"
    elct=-1
    i=nwd '{} possible type default values
  else
    a=i : elct=0 : capts(s,i)
    w2="["+str(elct+ixb)+"]" 'array dimensioning
    rps=8
    hiex+=w1+"="+mid(s,a,i-a)+cr
  endif
  vars(wr+" "+w1+w2)
  ilc=1 : wr=gword(w1,1) 'returning var name
  skiplspace(s,i)
end macro



'   #####                      #####
'  ######                      ######
'  ##                              ##
'  ##   ##########    ##########   ##
'  ##  ############  ############  ##
'  ##  ##    \|/ ##  ##    \|/ ##  ##
'  ##  ##    -O- ##  ##    -O- ##  ##
'  ##  ##    /|\ ##  ##    /|\ ##  ##
'  ##  ############  ############  ##
'  ##   ##########    ##########   ##
'  ##                              ##
'  ######                      ######
'   #####                      #####


int fpnp
int nfnd
int shv

function mword(string*s, int*i ) as string
==========================================
  '
  'RESOLVES MACROS, CONSTANTS, LITERALS, VARIABLES, ATTRIBUTES, TYPES ETC
  '
  ' s    source
  ' i    position in source
  ' swd  start of word position
  ' a    ascii code
  ' b    general purpose
  ' k    general purpose
  ' wr   word
  ' wk   struc or variable string
  ' wm   struc or variable string
  ' wn   gen
  '
    int a,b,c,k,m,n,v,kn
    string wr,wk,wm,wn,wo,w1,w2
    '
    gwc++
    '
    =======
    rmword:
    '======
    '
    'HUGE RECURSION CHECK
    wct++
    'if wct>=0x80000 '320K words
    '  ert=102 : goto exitmword2
    'endif
    '
    'GLOBAL STATE VARIABLES
    typ=0     'type
    varf=0    'member code
    elsize=0  'element size
    mc=0      'metatype code
    mp=0      'record index
    woff=0    'method offset
    nfnd=0    'not-found flag
    '
    '
    wr=tword(s,i)
    '
    sttw=swd
    ow=wr
    owa=wr
    if lenw=0
      goto exitmword1
    endif
    '
    'WITH prefix
    '
    if wthf
      if ascw=46
        if asc(wr,2)=46
          wr=wths+mid(wr,3)
        else
          wr=wths+wr
        endif
        inserts(s,wr,i)
        wr=tword(s,i)
        ow=wr
      endif
    endif
    '
    if nmb
      goto numberq
    elseif dtf=1
      goto exitmword3 'DOT LABEL
    endif
    '
    '
    'CHECK FOR COLON LABELS
    '----------------------
    '
    if newline
      if (ascn=58)and(ascw>64)
        if swd+lenw=i
          a=i+1 : skiplspace(s,a)
          if ise(ascn)
            i=swd
            mid(s,i,"."+ow) 'CONVERTED TO DOT LABEL
            goto rmword
          endif
          ascn=58
        endif
      endif
    endif
    '
    '
    wredo:
    '=====
    '
    if qot
      goto quotyp
    endif
    '
    if ascw>=252 'MARKER SYMBOLS
      goto exitmword1
    endif
    '
    if ascw=35
      if wr="#unquote"
        wr=noquotes(tword(s,i))
        inserts(s,wr,i)
        goto rmword
      elseif wr="#tally"
        elct=0
        capts(s,i)
        wr=str(elct+1)
        typ=4 : goto exitmword1
      endif
    endif
    '
    wk=""
    '
    'ASSEMBLER OPERANDS
    '------------------
    '
    if ascw=91
      wr=ResolveAsm(s,i)
      owa=wr
      if ascw<>91
        wk=wr+" " : goto insertd 'RECURSE WITH VARIABLE NAME
      endif
      goto exitmword3
    endif '[..]  91
    '
    '
    '
    quotyp: 'determine literal string type
    '=====================================
    '
    if qot
      '
      'combine string literals
      a=ascw
      while a=ascn
        b=lenw-1
        wk=tword(s,i)
        wr=mid(wr,1,b)+mid(wk,2,lenw-1)
        lenw=len(wr)
      wend
      '
      mc=-32
      if asc(wr,2)=iqq-1
        typ=0xc2
        sog="wbstring"
      else
        typ=0xc1
        sog="bstring"
      endif
      goto exitmword1
    endif
    '
    numberq: 'LITERAL NUMBERS CHECK
    '==============================
    '
    if nmb
      b=swd
      wordval(s,swd,i)
      if nan=0
        mc=-31 'NUM LITERAL
        if dtf
          if fpnp 'floating point number precision
            typ=&h68 : lent=8 : sog="double"
          else
            typ=&h64 : lent=4 : sog="single"
          endif
        else
          typ=4 : lent=4 : sog="int"
        endif
        wr=mid(s,b,i-b)
        goto exitmword1
      endif
    elseif lenw=1
      if (ascw>=36)and(ascw<=64) 'SYMBOL GROUPS
        goto exitmword3
      endif
    endif
    '
    '========
    lookupwr:
    '========
    '
    if lenw=1
      if ascw=35
        if nisxn
          wr="#"+tword(s,i) '#KEYWORD
        endif
      endif
    endif
    '
    'LOOKUPM SUPPORTS NAMESPACE NOTATION: A::B
    '
    if wr="prior"
      prv=1
      wr=tword(s,i)
      owa="prior "+wr
      ow=wr
    endif
    '
    mp=identwr(wr,wk)
    '
    if mp=0
      if ascw=35
        if asc(wr,2)=35
          goto exitmword2
        endif
        sys p=getvarptr(wr)
        if p
          wr=str(p) : nan=0 : goto exitmword3
        else
          ers="Host variable not found" : ert=4004
          return wr
        endif
      endif
      nfnd=1
      goto exitmword2
    endif
    '
    mc=drc(mp).a  'METATYPE OR TYPE
    '
    if mc<0
      if mc=-1
        mc=0
        mp=drc(mp).f
        jmp fwd shvar
      elseif (mc=-3)or(mc=-8)or(mc=-15)or(ascn=123)
        a=i
        nextinstruct(s,i)
        typ=identype(wr)
        '
        'MULTIASSIGN
        if ascn=123 'EG: double {1,2,3,4,5}
          if typ
            elsz=lent
            dataset()
            'REPROCESS INSERTED TEMP OPERAND
            goto wredo
          endif
        endif
        i=a : skiplspace(s,i)
        if dtf>1
          goto isdtf 'CLASS MEMBERS DIRECT
        endif
      elseif mc=-14
        a=drc(mp).f
        if (newline=0)or(cnd<>0)
          c=0
          if a=44 'indexbase
            b=ixb : c=1
          elseif a=51  '#majorminor
            b=1-arcm : c=1
          elseif a=52  '#minormajor
            b=arcm : c=1
          endif
          if c
            inserts(s,str(b)+" ",i)
            goto rmword
          endif
        endif    
        'function= sub= method= etc
        if (a=9)or(a=10)or(a=11)
          a=0
          b=dtf
          if dtf
            a=1
          elseif isxn
            a=1
          elseif (ascn=41)or(ascn=93)or(ascn=125)
            a=1
          else
            c=i
            if identop(s,i,c)
              a=1
            endif
            skiplspace(s,i)
          endif
          if a
            wr="returnvar"
            'b orig dtf
            if b
              wr+="."+wk : dtf=10
            endif
            lenw=len(wr)
            goto lookupwr
          endif
        endif
      endif
      goto mwcases        'NOT A VARIABLE OR CONSTANT
    endif 'mc<0
    '
    if shv>0
      if mp<shv
        ert=502 : ers="Not shared:"
        jmp fwd exitmword2
      endif
    endif
    '
    shvar:
    ======
    '
    typ=drc(mp).f 'RESOLVED TYPE
    if drc(mp).h and 1
      cnstr=1
      '
      wr=mrcso(mp,1)
      ascw=asc(wr)
      if ascw=61
        wr=mid(wr,2)
        ascw=asc(wr)
        if isn(ascw)
          mc=-31
        endif
        goto exitmword1 'CONST
      endif
      '
    endif

    isdtf: 'IS IT A DOT NAME?
    '========================
    '
    if dtf>1
      '
      '
      'MEMBER TYPES
      '------------
      '
      k=-1
      w1=wr
      findmember(wk,wr,k)
      if k=0
        ert=402 : ers="Member not found : "+ow
      elseif (funn<>13)and(funn<>14)
        if mp=ths
          if (varf=1)or(varf=3)
            ert=405 : ers="Uninstantiated class"
          endif
        endif
      endif
      '
      if ert
        wr=ow : goto exitmword3
      endif
      '
      if ascn=91
        goto arrfix
      endif
      if ascn=lbr
        if varf<8
          goto arrfix
        endif
      endif
      goto exitmword3 'EXCLUDE FUNCTION ARRAY AND PARAMS
      '
    endif 'dtf
    '
    'NON DOTTED NAMES
    '================
    '
    wr=mrcso(mp,1)
    if asc(wr,2)=35 '[#var]
      m=2
      swd=1
      wr=ResolveAsm(wr,m)
    endif
    '
    'CHECK FOR WPFX: dim b at p.member
    splitoperand(wr)
    '
    lent=drc(mp).b
    ind=drc(mp).d
    'indt=drc(mp).e
    if ind
      wbse=wr
      if cpoint=0
        indiri(wr,ind) : wr=pedi
      endif
    endif
    w1=mrcso(mp,3)
    a=1
    sog=tword(w1,a)
    '
    if ascn>32
      sig=mid(w1,a) : varf=8 'FUNCTION POINTER WITH SIGNATURE
    endif
    '
    skiplspace(s,i) 'RESTORE ORIGINAL ASCN
    '
    '
    '======
    arrfix: 'ARRAY RESOLUTION
    '======
    '
    select ascn
    case 40 '(
    case 91 '[
    case else goto exitmword3
    end select
    '
    a=i
    c=i
    do
      capture(s,m,a,0)
      if asc(s,a)=46
        ilc=1 : w1=gword(s,a)
        if ascn=91
          continue do
        endif
      endif
      exit do
    loop
    w1=ow+mid(s,c,a-c)
    skiplspace(s,i)
    '
    if ascn=91
      fixsqbr(s,i)
      i++
      w2=precedence(s,i,0)
      inserts(s,"("+w2,i)
      ascn=lbr
    else
      if nobr=1
        if ascn=lbr
          nobr=0 'CLEAR ARRAY SUPPRESSION FLAG
        endif
        goto exitmword3 'INHIBIT ARRAY INTERPRETATION
      endif
    endif
    '
    if ascn=lbr
      wpfx=arrayres(s,i,wr) 'wr/wg is also altered in express()
    endif
    '
    'VARIABLE: [ebx+4096] [#12345678] ecx OR NUM CONST 0x123 ETC
    '
    owa=w1 'CAPTURE OUTERMOST (...) AND MEMBERS AND MEMBER ARRAYS
    goto exitmword3
    '
    '
    '=======
    mwcases:
    '=======
    '
    if nmac=1
      select mc
      case -18,-19,-20,-21
        goto exitmword3
      end select
    endif
    '
    select mc
    '
    case -3  : goto exitmword1 'TYPE OR CLASS
    case -4  : varf=8 : goto exitmword1                 'UNPROTOTYPED PROCEDURES
    case -5  : varf=8 : goto exitmword1                 'LABELED OR VECTORED PROCEDURES
   'case -7  : goto exitmword1                          'USER DEFINED OPERATOR
    case -8  : goto exitmword1                          'DEF TYPE
    case -9  : goto exitmword1                          'COMMON RESERVED WORDS
    case -10 : typ=drc(mp).f : lent=drc(mp).b
               sog=mrcso(mp,3) : goto exitmword3        'REGISTERS
    case -11 : wk=attributes(s,i)
               goto insertd
   'case -12                                            'NAMESPACE RECORD, NOT ACCESSIBLE

    case -13 :'PRIMARY KEYWORDS
               goto exitmword1

    case -14 :'PRIMARY KEYWORDS
               goto exitmword1

    case -15 :'C PRIMITIVE TYPES
               ctype(s,i,wr)
               goto exitmword3

    case -16 :'CORE FUNCTIONS
               varf=8 : goto exitmword1

    case -17 :'DEFF FPU MATH ASM MACRO CALL
               goto exitmword1
 
    case -18 :'% $ EQUATE / DEF MACRO CALL
               wk=lomac(mp,s,i)
               'if shd
               '  print "macro: " ow cr cr wk
               'endif 
               goto insertd

    case -19 :'DEFX SYSTEM TERMINATION MACRO CALL
               wk=mrcso(mp,1)+ " " : tmnt=1
               if epgi[0] '#ENDING
                 wk=left(epgs(0)+wk,epgi[0])
                 epgi[0]=0
               endif
               goto insertd

    case -20 :'MACRO(...) CALL
               '
               'itr operator type recursion checks
               '
               wk=himac(mp,s,i)
               'if shd
               '  print "macro: " ow cr cr wk
               'endif 
               goto insertd

    case -22 :'INTERNAL CODE MACRO CALL
               goto exitmword3

    case -29 : goto exitmword2 'SUBROUTINE LABEL RECORD

    case -30 : goto exitmword2 'LABEL RECORD

   'case -31 :'NUMBER LITERAL ALREADY PROCESSED

   'case -32 :'STRING LITERAL ALREADY PROCESSED

    case -33 :'ENUMERATION DOT MEMBERS
               if wk
                 wr=str(dic(mrcso(mp,1),wk))
               endif
               goto exitmword3
   '
    end select
    '=========
    '
    '
    'CORRUPTION CHECK
    '
    ers="unclassified Word " : ert=123
    goto exitmword3
    '
    insertd:
    '=======
    '
    if ert
      exit function
    endif
    '
    if wk
      inserts(s,wk,i)
    endif
    '
    'RECURSION CHECK
    dct++ 'each inserted word
    if dct>200
      ert=102 : goto exitmword2
    endif
    goto rmword
    '
    exitmword3:
    '=========
    '
    lenw=len(wr)
    '
    exitmword2:
    '==========
    '
    ascw=asc(wr)
    '
    exitmword1:
    '==========
    '
    return wr
    '
end function




'
'  ###################
'  #    NUMBERS      #        #       #  #  #    ###          ###    ##    #
'  #    STRINGS      #         ##      #####     #              #    # #   #
'  #    ADDRESES     # ############  ## PFX ##   # REG + OFFSET #    #  #  #
'  #    POINTERS     #         ##      #####     #              #    #   # #
'  #    VARIABLES    #        #       #  #  #    ###          ###    #    ##
'  ###################



function pword(string*s, int*i) as string
=========================================
  '
  'RESOLVES POINTERS / ADDRESSES, CASTING ETC
  '
  int a,b,c,d,e,k,m,n,p,v,ty,tyc,gg,da, tm
  string wr,ws,wt
  '
  ind=0 : nan=1 : wpfx="" : ou="" : typk=0
  '
  '
  '============================
  'RECURSION POINT
  ' (FOLLOWING MACRO EXPANSION)
  '============================
  '
  '-----------
  'INDIRECTION * **********
  'and CASTING
  '===========
  '
  b=0 'POINTER '*' COUNTER
  '
  do
    wr=mword(s,i)
    '
    if (dtf<>0)and(funi<>0)
      'DISCOVER STRING MEMBERS BEING USED IN A FUNCTION
      if isstr(typ)
        lcls=1 'ENSURE STRING BUFFERS ARE MADE AVAILABLE
      endif
    endif
    if (nan=0)or(qot=1)
      goto xpword 'literal numbers and quotes
    endif
    '
    if isc(ascw)
      goto xpword
    endif
    '
    if ert
      wr=ow : exit function
    endif
    '
    if mc=-14
      select ascw
      case 0x74
        if wr="that"
          nth=1 : continue do
        endif
      end select
    endif

    '
    'WORDS STARTING WITH DOT
    '-----------------------
    '
    if dtf=1
      if lenw=1
        ers="isolated dot" :ert=502
      endif
      goto xpword
    endif
    '
    'CASTING EG: (HANDLE) (void *) H
    '===============================
    '
    if ascw=0x62 'b
      if wr="byval"
        bvg=1
        if isfpu(typ)
          ty=cpuw
        endif
        continue do
      endif
      if wr="bycopy"
        a=i
        while ascn=lbr
          i+=1
          skiplspace(s,i)
        wend
        wr=wordahead(s,i)
        wr=mword(wr,1) 'find sog type
        wr=newtmpvar(sog)
        captsx(s,i)
        hiex+=wr+"="+mid(s,a,i-a)+cr
        rps=1
        inserts(s,wr,i)
        continue do
      endif
    endif
    '
    'DETECT EXPLICIT CASTING
    '-----------------------
    '
    c=0 : d=0 : m=swd
    if ascw=99
      if wr="cast"
        d=4 'CAST
        if ascn=lbr
          ascw=ascn : i++ : d=1 'CAST(
        endif
      endif
    elseif ascw=lbr
      d=1 '(
    endif 'd identify casting expression
    '
    'INTERPRET CASTING 
    '-----------------
    '
    ' a = (long) b
    ' a = cast long b
    ' a = cast (long) b
    ' a = cast (typeof x) b
    ' a = cast (long *) b
    ' a = cast (long ptr) b
    '
    if d
      ws=wordahead(s,i)
      if ws="typeof"
        i=nwd
        ws=mword(s,i)
        c=typ
        nwd=i
      else
        c=identype(ws)
      endif 'c identify type
      if d>1
        if c
          i=nwd
          skiplspace(s,i)
        else
          ert=301 : ers="Unidentified cast "+ws
        endif
      else 'd<=1
        if c=0
          'NOT A TYPE CAST
          if wr="cast"
            ert=301 : ers="Unidentified cast "+ws
          else
            ascw=lbr
            lenw=1         
          endif
          exit do 'mword iteration loop
        endif
        a=i
        i=nwd
        b+=isptr(s,i)
        if ascn=rbr
          i++
          skiplspace(s,i) '(DOUBLE*) END BRACKET
        else
          'NOT A TYPE CAST
          i=a
          skiplspace(s,i)
          ascw=lbr
          lenw=1         
          exit do
        endif
      endif 'd<=1
      '
      'CAST IDENTIFIED?
      '
      if c
        tyc=c : tm=typr : typr=c
        b+=indt 'TYPE INDIRECTION
        continue do 'NEXT WORD OR CAST EXPRESSION
      endif 'c cast identified
    endif 'casting analysis
    '
    '
    '
    'INDIRECTION SYMBOLS * ? &
    '-------------------------
    '
    if ascw=63
      ty=cpuw : ou+=wr : continue do '?'
    endif
    if ascw<>42
      exit do '*'
    endif
    if ascn=61
      exit do  '*='
    endif
    '
    b++ : ou+=wr : 'TALLY '*' INDIRECTION
    '
    '
  loop 'mword iteration loop
  '
  'itr function returning pointers.
  '
  if varf>=8
    if varf>8
      mc=-5
    endif
    if tyc
      ou="" : b=0 'suppress cast ptrs: cast char * fn
    endif
  endif
  '
  'INDIRECTION ENCODING
  '--------------------
  '
  if b=0
    if (cpoint>0)and(ascw=91)
      a=drc(mp).d
      if a>0 'POINTER VARIABLE
        if wpfx=""
          ty=cpuw 'TREAT AS POINTER (EXCEPT ARRAY)
        endif
      endif
    endif
  else 'b>0' POINTERING
    '
    if ascw=91
      '
      if mp
        if ascn=91
          fixsqbr(s,i) '[..] to (..)
        endif
      endif
      '
      'prefix wpfx updated
      '
      if (cpoint=0)or(wpfx="")
        if cpoint
          ind=0
        endif
        indiri(wr,b)
        ind+=b
        wr=pedi
        lenw=5
      endif
      '
      if cpoint
        if ind<>drc(mp).d
          ty=cpuw
        endif
      else
        ty=cpuw ' TYPE OVERRIDE
      endif
      '
    elseif ascw=lbr '*(A+B) ETC
      ind+=b
      ty=cpuw
    endif
    '
    if typ=0  '*(A+B) ETC
      indiri(cpua,b)
      if ascw=lbr
        wt=wpfx
        a=cpuw
        c=op
        op=1
        nst++
        wpfx="|op 4 F "+cr+express(s,i,a)+wt+"|op 6 F "+cr
        if (ascn=rbr)or(ascn=93)
          i++ : skiplspace(s,i)
          nst--
        endif
        typ=cpuw
        nan=1
        op=c
        wr=pedi
        ascw=91
        lenw=5
        goto xpword
      endif
    endif
  endif
  '
  '
  '
  '
  '================
  'ADDRESSES & or @
  '================
  '
  if (ascw=38)or(ascw=64)
    '
    if ascw=64
      i=swd+1 : skiplspace(s,i)
    endif
    '
    ou+=wr ' capture indirection
    '
    'ADDRESS OF STRING LITERAL
    '-------------------------
    '
    if (ascn=38)or(ascn=64)
      da=1
      i++ 'double address && or @@
    endif
    '
    '
    'ADDRESS OF ARRAY ELEMENT
    '------------------------
    '
    ws=ou
    wr=pword(s,i) 'RECURSE
    ou=ws+ou
    '
    'ADDRESS OF LITERAL NUMBER (PLACE IN TEMP VAR)
    '
    if mc=-31
      wpfx="" : a=0 : b=typ
      if (op>1)and(b=cpuw)
        wpfx=operi(4,b,qeax) : a=1
      endif
      ws=tmpvar()
      wpfx+=operi(1,b,wr)+operi(2,b,ws)+leaedi(ws)
      wr=qedi : typ=cpuw : mc=0 : nan=1
      if a
        wpfx+=operi(6,b,qeax)
      endif
      goto xpwordx
    endif
    '
    typ=cpuw
    '
    if isq(ascw)
      wpfx="|qu "+wr+cr : wr=cpua : ty=cpuw : goto xpword 'address of string data
    endif
    if asc(wpfx)=0x6f
      ty=cpuw : goto xpword 'address of const o2 ....
    endif
    '
    '
    '
    'RENDER PROCS AS PLAIN VARIABLES
    '-------------------------------
    '
    '
    if (ascw=91)or(mc=-3)or(mc=-4)or(mc=-5)or(ascw=38)
      '
      if varf=8
        '
        if ascw<>91
          a=ascn
          nextproc(mp,wr,b) 'itr function overloading / match signatures
          if b
            wr=addlproc(b,wr)
          endif
          ascw=asc(wr) : ascn=a
        endif
        mc=0
        varf=1
        typ=cpuw
        if ascw<>91
           typ=cpuw
         'NO VECTOR?
          if ascn=61
            ert=300
            ers="Must refer to a proc pointer: "+wr
          else
            goto addrlab 'ASSUME TO BE A LABELLED FUNCTION
          endif
        endif
        '
        goto xpwordx
        '
      elseif varf>8
        '
        'ITR not for com  like methods with remote VA
        '
        'ADDRESS OF (NON DLL) VIRTUAL FUNCTION
        '
        'CHECK FOR PRESENCE OF METHODS TABLE
        '
        a=0
        if drc(mp).a=-3
          if drc(mp).c
            a=1 'IS A CLASS RATHER THAN AN OBJECT
          endif
        elseif mc>0
          p=drc(mp).a-typh
          if drc(p).c
            a=1 'OTHERWISE CHECK THE CLASS OF THE OBJECT
          endif
        endif
        '
        if a=1
          '
          'ACCESS FUNCTION TABLE DIRECTLY
          '
          wr=memreg(regst,toff+woff)
          if da
            wpfx=leaedi(wr)
            wr=qedi
          endif
          '
        else
          '
          'METHODS TABLE NOT DEFINED SO ASSUME
          'EXTERNAL WITH VIRTUAL TABLE POINTER
          '
          indiri(wr,1)
          ind++
          wr=memreg(qedi,woff)
        endif
        mc=0 : dtf=0
        varf=1 : goto xpwordx
      endif 'PROCEDURES
      '
      '
      'ADDRESS OF VARIABLE [ebx+/-offset] etc
      '--------------------------------------
      '
      varaddr(wr,da)
      '
      if da 
        ers="Invalid @@ address" : ert=7 : goto xpword
      endif
      '
      goto xpwordx
      '
    endif '[..] OPERANDS
    '
    addrlab:
    '=======
    '
    typ=cpuw
    varf=1
    pls="0"
    if (mc=-4)or(mc=-5)
      mc=0
      a=1
      nextproc(mp,wt,0) 'itr overload matching?
      typ=cpuw
      varf=1
      sig=""
      sog=""
      skiplspace(s,i)
      wr=wt
      int ta=asc(wt)
      if isa(ta)=0
        goto xpwordx 'vector
      endif
    endif
    wpfx="|ab "+pls+" "+wr+" "+hex(nsp)+" "+hex(nsi)+cr
    wr=qedi
    nfnd=0
    goto xpwordx
    '
  endif 'LABELS
  '
  '
  '
  xpword:
  '======
  '
  if tyc
    ty=tyc : typr=tm : sog=ws
  endif
  if ty
    typ=ty : typk=ty 'typk cast type
  endif
  if ou
    owa=ou+owa
  endif
  return wr 
  '
  xpwordx:
  '======
  ascw=asc(wr)
  lenw=len(wr)
  goto xpword

end function 'pword



function lexiword(string*s, int*i) as string
============================================
  string wr
  int a
  wr=xword(s,i)
  ''MACRO SUPPORT
  int g=asc(wr)
  if isq(g)=0
    if instrchars(wr,"$:/\.<>")=0
      wr=pword(wr,1) 'CHECK FOR MACRO
    endif
  endif
  wr=noquotes(wr)
  ascw=asc(wr)
  lenw=len(wr)
  skiplspace(s,i)
  return wr
end function





procedure erasek(string*w1,*w2, int b,c)
========================================
  '
  'ERASE KEYWORD IN A STRING AND C WORDS FOLLOWING
  '
  int f,m
  string w3
  '
  f=instr(b,w1,w2)
  if f=0
    exit procedure
  endif
  m=f : f+=len(w2)
  do
    c--
    if c<0
      exit do
    endif
    w3=mword(w1,f)
  loop
  midspace(w1,m,f) 'erase section
end procedure




function rootpath(string*wr) as string
======================================
  static string rco
  if asc(wr)<>36
    return wr 'exclude when no '$' prefix
  endif
  int    a,b,e,j
  static ubyte *p,*q,*r
  '
  if rco="" 'GET MODULE FILE PATH
    char rbuf[256]
    'p=GetCommandLine
    @p=strptr(rbuf)
    GetModuleFileName(0,rbuf,256)
    if p=34
      a=34
      @p++
    else
      a=0
    endif
    @q=@p
    do
      if (q=a)or(q=0)
        exit do
      endif
      @q++
    loop
    e=@q-@p
    @q=@p
    @r=@p
    rco=space(e)
    for j=1 to e
      if (q=47)or(q=92)
        @r=@q
      endif
      mid(rco,j)=chr(q)
      @q++
    next
    rco=left(rco,@r-@p)
  endif
  j=2
  a=asc(wr,2)
  if (a=47)or(a=92)
    j++
  else 
    a=47
  endif
  if @r=@p
    return mid(wr,j)
  else
    return rco+chr(a)+mid(wr,j)
  endif
end function



procedure paths(string*s, int*i, string*pth)
============================================
  int b
  string wr
  if ascn=43
    b=1 : i++
  elseif ascn=45
    b=2 : i++
  endif
  wr=lexiword(s,i)
  '
  if b=1
    pth+=wr
  elseif b=2
    b=len(pth)-len(wr)
    if b>=0
      pth=left(pth,b)
    endif
  else
    pth=rootpath(wr)
  endif
end procedure



function filename(string*s) as string
=====================================
  'strip file path from file name
  int a,b
  do
    a=b+1
    b=instr(a,s,":")
    if b
      continue do
    endif
    b=instr(a,s,"\")
    if b
      continue do
    endif
    b=instr(a,s,"/")
    if b
      continue do
    endif
    exit do
  loop
  function=mid(s,a)
end function



function issub(string*s, int*i) as int
======================================
  long a
  string w1
  w1=wordahead(s,i) : a=asc(s,nwd)
  if asc(w1)=91
    function=0 'SUB [] ...
  elseif a=lbr
    function=-1 'SUB XXX(
  elseif a=44
    function=0 'SUB XXX,
    w1=wordahead(s,nwd) : a=asc(s,nwd) ',..MULTILINE SUB
    if ise(a)
      function=-1 'SUB A, endline
    endif
  elseif idword(" byte word dword qword eword ptr float ",w1)
    function=0 'SUB WORD ...
  else
    function=-1
  endif
end function




