

function splitderef(int a) as string
'===================================
  int    b=1
  string w1=""
  '
  if a=0
    mid(wpfx,1)="lea" 'substituting mov
    b=instr(b,wpfx,"]")+3
    w1=deref(qedi)
  else
    do
      if a<=0
        exit do
      endif
      b=instr(b,wpfx,cr)+2 'eg "mov edi,[ebx+5000]"+cr
      a--
    loop
  endif
  '
  w1+=mid(wpfx,b)
  wpfx=left(wpfx,b-1)
  return w1
end function


int dprm 'additional stackspace for UDT
int aprm[5]
'
function callcnv(int pn, string*w2, int e) as string
=====================================================
  int a,b,w,pa
  string w1,w3
  int ty=typg
  '
  if e>48
    typg=cpuw
  elseif typg>=typh
    '
  elseif typg>0xa0
    typg=cpuw
  endif
  '
  if coret
    pn+=2  'DIRECT RETURNS
  elseif vaf>8
    pn++  'OBJECTS
  endif
  '
  pa=pn
  pn+=dprm 'EXCESS DIRECT UDT DATA
  '
  'DIRECT BYVAL UDT
  ---------------------
  if ty>=typh and e<=48
  ---------------------
  '
  'bycopy is a better option
  'ers="UDT must be passed byref"
  'ert=403
  'return ""
  '
  a=lent 'from compatsig identype
  roundupc(a,cpuw)
  '
  'itr when cpuw=8
  if (cco=2)or(cco=3)
    w3="lea rdi,"+memreg(qesp,pn*cpuw-cpuw)
  else 'stdcall / cdecl
    w3="sub rsp,"+a+cr+"  mov rdi,rsp"
  endif
  if asc(w2)=91
    w1="  lea rax,"+w2
  endif
  w1+="
  mov rsi,rax
  "+w3+"
  mov ecx,"+a+"
  (
   sub ecx,4
   jl exit
   mov eax,[rsi]
   mov [rdi],eax
   add rsi,4
   add rdi,4
   repeat
  )
  "
  stkb+=a-cpuw 'CDECL stack adjust
  b=(a-1)\cpuw
  if pa<=4
    aprm(pa)=b 'additional stack units
  endif
  dprm+=b
  return w1
  -----------
  endif
  -----------
  '
  '64BIT CALLING
  '
  if cpuw=8
  if (cco=1)or(cco=2)or(cco=3)
    '
    'w2 source operand
    'w3 target operand
    w3=memreg(qesp,pn*8-8)
    '
    if isfpu(typg)=0 'NON-FLOATS
      '
      if idword(" rax eax ax al ",w2)
        w1=""
      else
        w1=oper(1,typg,w2)
      endif
      '
      if typg<0x40
        'if (typg and 15)<>cpuw
        '  w1+=cvta(typg,cpuw)
        'endif
        if (typg and 15)<4
          w1+=cvta(typg,4)
        endif
      endif
      w1+=oper(2,cpuw,w3) 'ALWAYS USE STACK
    elseif typg=0x40
      exit function 'FPU INTERNAL STACK TYPE
    else ' typg>0x40 DIRECT FLOATS
      if asc(w2)<>91
        w1=""
      else
        w1=oper(1,typg,w2)
      endif
      w1+=oper(2,typg,w3) 'USE STACK
    endif
    goto xcallcnv
  endif 'cco
  endif 'cpuw=8

  if cco=16
    w1=rgp(pn)+w2+cr 'CPU: PARAMS IN REGISTERS
  elseif cco=17
    w1="" 'PARAM REMAINS ON FPU STACK
  else 'NOT MS64
    'itr quads on 32bit cpu
    w1=oper(4,typg,w2) 'push onto stack (also supports double floats byval) 
  endif
  xcallcnv:
  typg=ty
  return w1
end function


function cvtai(int typa, typb) as string
========================================
'cv
string w1
dtf=0
if typa<>typb
  double ta=typa, tb=typb 'PREVENT CVT RECURSION
  w1="|cv "+hex(ta)+" "+hex(tb)+cr
  return w1
endif
end function


function logas() as string
==========================
  if dts<0
    dts=1
  else
    dts++
  endif
  if funi
    lcl=1 : lcls=1
  endif
  return rtl(asstmpa) 'TEMP LIST FOR DELETION
end function


function strinit(string*wp,*wr, int*a) as string
================================================
  string w2,w3
  a=strinstga
  w3=wp+wr
  if instr(w3,"["+qebp+"-")
    a=strinstla
  elseif ths=0
    if instr(w3,"["+qebp+"+")
      a=0 'no need to check
    endif
  endif
  '
  w2="lea "+qecx+cm+wr+cr
  if a
    w2+=rtl(a) 'if string is null: create one
  endif
  return w2
end function


function returns() as string
============================
  '
  'BYTES TO DISCARD FROM STACK WHEN RETURNING
  '------------------------------------------
  '
  int a            'CDECL FASTCALL ADJUST
  int b=ccp        'CALLING CONVENTION
  drc(mqf).b=reto  'LENGTH OF PARAMS
  '
  'APPLIES TO STDCALL AND PASCAL ONLY
  '
  if (ccp=0)or(ccp=8)
    if reto
      return "ret "+str(reto)+cr 'but not with ellipsis (auto cdecl)
    endif
  endif
  if ccp=1 'cdecl
    if crgd=0x20 'thiscall
      if clsi
        return "ret 4"+cr      
      endif
    endif
    if crgd=0x40 'fastcall
      a=reto
      if a>8
        a=8 'max 2 regs
      endif 
      return "ret "+str(a)+cr      
    endif
  endif
  return "ret"+cr
end function



function releaselocalbuffers() as string
========================================
  int d
  string w1
  'lcls 'LOCAL STRINGS
  'dts   'TEMP STRINGS
  'dcs   'CONCATENATION BUFFER
  d=lcls or dts or dcs
  '
  'SAVE RETURN REGISTERS
  '
  if d
    w1+=operi(4,cpuw,qeax)+operi(4,cpuw,qedx)
  endif
  '
  'RELEASE LOCAL STRINGS
  '---------------------
  '
  if lcls
    w1+=rtl(delloca)
  endif
  '
  'RELEASE TEMP STRINGS
  '--------------------
  '
  if dts
    if dts>0
      w1+=rtl(deltmpa)
    endif
    if cpuw=4
      w1+=operi(4,4,"[ebp-8]")+rtl(16)
    else 'cpuw=8
      w1+="mov rcx,[rbp-16]"+cr+rtl(16)
    endif
  endif
  '
  'RELEASE CONCATENATION BUFFER
  '----------------------------
  '
  if dcs
    if cpuw=4
      w1+=operi(4,4,"[ebp-12]")+rtl(16)
    else 'cpuw=8
      w1+="mov rcx,[rbp-24]"+cr+rtl(16)
    endif
  endif
  '
  'RESTORE RETURN REGISTERS
  '------------------------
  '
  if d
    w1+=operi(6,cpuw,qedx)+operi(6,cpuw,qeax)
  endif
  return w1
end function



procedure replaceregs(string*s, int b,e, string*r1,*r2)
=======================================================
int a
a=b
do
  a=instr(a,s,r1)
  if (a=0)or(a>e)
    exit do
  endif
  mid(s,a)=r2
  a+=3
loop
end procedure


procedure PrepForLocalSpace(int pn)
========================================
  int a,i
  string w1,w3,w4
  '
  'asce=-1
  aoffl=-cpuw*3  'allow for string lists
  aoff=aoffl
  blcl=j 'PATCH POSITION FOR STACK INSTRUCTION
  w1=""
  if cpuw=4
    if clsi
      if crgd=0x20 'thiscall
        w1+="pop eax : push ecx : push eax"+cr
      endif
    endif
    if crgd=0x40 'fastcall
      'paramcount pn
      if pn=1
        w1+="pop eax : push ecx : push eax"+cr
      endif
      if pn>=2
        w1+="pop eax : push edx : push ecx : push eax"+cr
      endif      
    endif
    replacecolons(w1)
  endif
  '
  if atf
    w1+=storeregs
  endif
  '
  w1+=savestackptr
  '
  '
  if cpuw=8
    '
    'STORE REG PARAMS ONTO STACK
    '
    'but only necessary for external procs
    '
    a=16
    '
    if atf
      a=48
      w1+=memregspill(a,pn) 'SPILL REG PARAMS IN 64 BIT MODE
    endif
    w1+="and rsp,-16"+cr 'ROUND RSP DOWN TO NEXT 16 BYTE BOUNDARY
  endif
  '
  appendt(w1)
  plcl=j 'PATCH POSITION FOR STACK ALLOCATION
  appendt("|sp -64"+space(5)+cr)
  '
  '
  a=0
  '
  'RETURNED VARIABLE
  '
  if (wva(1)<>"")and(ccp<>17)
    '
    a=typp
    w3=" returnvar"
    '
    if a<typh
      if a=&h40
        a=&h68 : wva(1)="double" 'fpu return type using qword slot
      endif
      a and=31
      vars(wva(1)+w3)
    endif
    '
    '
  endif 'RETURN VARIABLE
  '
  'RESERVE STACKSPACE FOR RETURN VAR AND TMP/LOC STRING DEATH LISTS
  '
  a+=3*cpuw 'ALLOWING FOR LISTS
  '
  'ENSURE 16 BYTE ALIGNMENT FOR 64 BIT
  '
  if cpuw=8
    if (a=24)or(a=40)
      a+=8 : aoff-=8 : aoffl=aoff
    endif
  endif
  '
  if a>0
    roundupc(a,cpuw)
  endif
  mlcl=a
  appendt("|si            "+cr) 'STACK FRAME INIT TO ZEROS
  '
end procedure


function managelocalbase() as string
====================================
  int a,b,c,d
  '
  d=mlcl
  if cpuw=8
    roundupc(d,16)
  endif
  if lcl
    mid(t,plcl)="|sp -"+str(d)+" "+cr  'SET LOCAL WORK SPACE
  endif
  if lcls=0
    a=3*cpuw 'NO GC / CAT SPACE IN USE
  endif
  if (noin<>0)and(lcls=0)
    d=0
  endif
  b=instr(plcl,t,"|si ")
  if d>a
    mid(t,b+4)=hex(d) 'INIT LOCAL WORK SPACE WITH ZEROS
  else
    mid(t,b)="    " 'NO LOCAL SPACE
  endif
  return restorestackptr
end function


procedure noprototype(string*wd,*w1)
====================================
  if asc(wg)=41
    'wd whole expression
    w1=""
  else
    wd=wpfx
    w1=wg
  endif
  if (isstr(typg)<>0)or(wg=qedi)
    typg=cpuw
  elseif (typg>=typh)and(bvg=0) 'bvg byval flag
    'passing direct higher types: rect etc
    if wpfx=""
      wd=leaedi(wg) : w1=qedi : typg=cpuw
    else  'wpfx
      if (wg=pedi)and(drc(mp).d=1) 'simple indirection level 1
        wd=""
        w1=mrcso(mp,1)
      else
        if wg<>pedi 'array offsets etc
          wd+=leaedi(wg)
        endif
        w1=qedi
      endif
    endif
    typg=cpuw
  endif
end procedure



procedure newcleanvar(string *wn,*wr,int p)
===========================================
  wn=newtmpvar(typename(p))
  if @wr 'param provided
    wr=mrcso(qme,1) 'vector
  endif
end procedure


function  buildparamblock(int pb, cc) as string
===============================================
  int a,b,c,d,k,m,n,p,q,r11
  string w1,w2,w3,w4
  '
  a=pc : b=pb+1 : c=-1
  '
  if mpfx
    'CREATE PREPARATORY CODE
    'FOR PARAM OBJECTS
    string w5=""
    string w6=""
    string dstr
    for d=b to a
      w2=pas(d)
      m=instr(w2,"#obj#")
      if m
        p=paj(d) 'type
        newcleanvar(w3,w5,p) 'itr strings
        w2=left(w2,m-1)+w5+mid(w2,m+5)
        m=instr(mpfx,"#obj#")
        mpfx=left(mpfx,m-1)+w3+mid(mpfx,m+5)
      endif
      pas(d)=w2
      if pet(d)>=typh
        pet(d)=cpuw 'ASSUME POINTER VALUE
      endif
    next
    hiex+=mpfx : rps=1
    mpfx=""
    d=0 : m=0 : n=0 : p=0
  endif
  '
  'PARAMETER ORDER 0..7 REVERSE,  8.. FORWARD
  '
  if cc>=8
    swap a,b
    c=1 'LEFT TO RIGHT STACKING
  endif
  '
  if cc=2
    p=0
    w1=""
    for d=a to b step -1
      w1+=pas(d)+pav(d)
      pas(d)="" : pav(d)=""
    next
  else
    d=a
    'ASCENDING OR DESCENDING ORDER ACCORDING TO C
    if pc>pb
      do
        w1+=pas(d)+pav(d)
        pav(d)=""
        if d=b
          exit do
        endif
        d+=c
      loop
    endif
  endif
  '
  w4=w1
  w1=""
  '
  if (cc=2)or(cc=3)
    '
    a=pc-pb
    '
    'LOAD STACKED PARAMS INTO REGISTERS
    '
    if (a>0)and(cc=2)
      c=1 'available registers
      d=a 'number of params
      if coret
        c+=2 : d+=2 'CALLER ORIGINATED RETURN
        'reserve 2 registers
      elseif varf>8
        c++ : d++ 'OOP PARAMS
        'reserve 1 register
      endif
      if d>4
        d=4 'register only the first 4 params
      endif
      '
      'c lowest unused reg
      'p highest used reg
      w1=hex(c)+" "+hex(p)+" "
      b=1 'pb offset
      k=c 'start params to processed
      'remaining registers
      while k<=d
        m=pet(pb+b)
        w1+=hex(m)+" "
        if m>=typh
          n=aprm[b] 'additional stack units
          while n>0
            if k<4
              w1+="8 "
            endif
            k++
            n--
            if d<4
              d++
            endif
          wend
        endif 'm>=typh
        b++ : k++
      wend
      w1=regparams(w1,1)+cr
    endif  
    '
    '
    'DETERMINE REQUIRED STACKSPACE
    '
    a+=dprm 'for direct UDT
    '
    if a<3
      a=3 'for 32 bytes
    elseif a<7
      a=7 'for 64 bytes
    endif
    'round up to nearest 16
    '
    mov eax,a
    shr eax,1
    shl eax,4
    add eax,16
    mov tmpstk,eax
    '
  endif
  return w4+w1
end function



function prepcall(string*wp,*w4,*wm, int cc,np) as string
=========================================================
  'wp  name of procedure
  'w4  encoding output
  'wm  name with signature
  'pls vector or not
  '
  string w1,w3,w5,w6
  int a,b,dt,vm,m,fc
  '
  'FUNCTION CALL
  '
  if varf<=8
    a=asc(w4)
    if a=91
      w3=""
    else
      if asc(pls)=48
        w3=", "
      else
        w3=pls+" "
      endif
      w4+=" "+hex(nsp)+" "+hex(nsi)
    endif
    if cpuw=4
      if crgd=0x40 'fastcall
        '0 1 or 2+ params
        w6="" : fc=0
        select np
        case 1        : fc=4 : w6="pop ecx"+cr
        case 2 to 256 : fc=8 : w6="pop ecx"+cr+"pop edx"+cr
        end select
        if fc
          if cc=1
            '#show {
            'stkb=stkb-fc*4 'itr compile time err
            '}
            stkb-=fc
          endif
        endif
        crgd=crg
        return w6+"|go 0 "+w3+w4+cr
      endif
    endif 'cpuw=4
    return "|go 0 "+w3+w4+cr
  endif 'varf<=8
  '
  '
  'METHOD CALL
  '===========
  '
  dt=drc(mq).c 'INTERNAL FUNCTION TABLE INDEX
  vm=drc(mq).d 'VIRTUAL MODALITY
  '
  if vm>1 'EXTERN VIRTUAL 
    dt=0  ' MUST USE EXTERNAL TABLE
  endif
  '
  if atx>1 'CURRENT EXTERN VIRTUAL
    vm=2
    dt=0
  endif
  '
  w5=memreg(regst,toff+woff) 'one or the other
  m=drc(mp).a-typh
  if m<0
    m=mp
  endif
  '
  if w4=w5
    w3="mov "+qecx+",0"+cr
    goto necxadjust
  endif
  a=varf-10
  if a<0
    a=0 'TO ADD MULTI-INHERIT OFFSET
  endif
  '
  w3="lea "+qecx+cm+memregadj(w4,a)+cr 'LOAD OBJECT ADDRESS
  '
  if vm>1
    'VIRTUAL TABLE POINTER IS USED TO GET METHOD
    w3+=operi(1,cpuw,pecx) 'LOAD VIRTUAL TABLE ADDRESS
  elseif vm
    'VIRTUAL TABLE POINTER IS INCLUDED IN OBJECT
    if vtq
      'INHERITED METHOD EXPECTS VTP OFFSET
    else
      'INHERITED METHOD EXPECTS NO VTP OFFSET
      w3+="add "+qecx+cm+str(cpuw)+cr
    endif
  endif
  '
  necxadjust:
  ===========
  '
  'INTERNAL OR EXTERNAL VFT
  '
  if dt=0 'NO INTERNAL FUNCTION TABLE
    if vm=0
      ert=302 : ers="Class must be EXTERNAL/COM"
    endif
    w5=memreg(cpua,woff) 'VIRTUAL FUNCTION ADDRESS
  endif
  '
  'COMPOSE THE CALL INCLUDING 'THIS' IN THE ECX REGISTER
  '
  if asc(pls)=48
    pls=","+mrcso(m,0)+"."+wm 'FWD REF REQUIRES NAMED CLASS.PROCEDURE
  endif
  '
  w5=pls+" "+w5+" "+hex(nsp)+" "+hex(nsi)
  '
  if (cc=2)or(cc=3) '64bit calls
    return w3+"mov [rsp],rcx"+cr+"|go 4 "+w5+cr
  elseif (cc=16)or(cc=17) 'cpu fpu regs
    return w3+"|go 4 "+w5+cr
  else 'cc=0 cc=1
    if cpuw=4
      if cc=1
        stkb+=4
      endif
      if crgd=0x20 'thiscall
        if cc=1
          stkb-=4
        endif
        'rcx not pushed
        crgd=crg
        return w3+"|go 4 "+w5+cr 'thiscall fastcall
      endif '0x20
      if crgd=0x40 'fastcall
        '0 or 1+ visible params
        w6="" : fc=0
        if np
          fc=4 : w6="pop edx"+cr
        endif
        if cc=1
          stkb=stkb-fc-4
        endif
        crgd=crg
        return w3+w6+"|go 4 "+w5+cr
      endif 'fastcall
    endif 'cpuw=4
    return w3+operi(4,cpuw,qecx)+"|go 4 "+w5+cr
  endif
end function 'prepcall


function compactassign(string*s, int*i,ty, string*w1) as int
============================================================
  'CPU number types: qword,dword,byte,word,long,short
  if (ty>=0x40)or(cpa>=71)
    exit function
  endif
  int a
  string w2
  if isn(ascn)
    w2=wordahead(s,i)
    a=ascl(s,nwd)
    if (isx(a)<>0)and(cpa<>14)and(cpa<>15) 'EXCLUDES *= /=
      w1=psg+operi(cpa,ty,identypes(ty)+wsg+cm+w2)
      i=nwd
      return -1
    endif
  endif
end function


function retvalue() as string
=============================
  int b
  int a=typp
  string w1,w2
  if (lcl=0)or(ccp=17)
    exit function
  endif
  b=lookupm("returnvar")
  if b=0
    exit function 'SUB
  endif
  w2=mrcso(b,1)
  if w2=qeax
    exit function
  endif
  '
  'ENCODE FOR RETURNING DIFFERENT TYPES
  '
  if a<0x80
    '
    if cpuw=8
      if a>=0x60
        if atf
          'itr any type conversion?
          a and=31
          w1="movss xmm0,"+w2+cr
          if a>=8
            mid(w1,5)="d" 'double: "movsd"
          endif
          return w1
        endif
      endif
    endif
    if a=0x40
      a=0x68 'fpu type assumes double type here
    endif
    w1=operi(1,a,w2) 'RETURN INTEGERS AND FLOATS
    if (a>40)and(a<0x4f)
      if cpuw=4
        w1="mov eax,"+w2+cr+"mov edx,"+memregadj(w2,4)+cr
      else
        w1="mov rax,"+w2+cr
      endif    
    endif
    '
  elseif (a>=0xe0)and(a<0x100)
    w1=medi+w2+cr+rtl(trbstra)  'RETURN STRINGS
  else
    w1=operi(1,cpuw,w2) 'DEFAULT RETURN FOR BSTRINGS / HIGHER TYPES / POINTERS
  endif
  '
  return w1
  '
end function



function numoperation(string*wr, int typa,*typc) as string
==========================================================
  'supports numeric conversions
  string w1,w2,w3
  int a,c,d,cn
  a=typa and 15 'width operand
  c=typc and 15 'width accum
  cn=ascn
  '
  'SET TYPE AND WIDTH OF ACCUM
  if typc=0
    typc=typa
    c=a
  endif
  '
  'UNSIGNED ACCUM AND SIGNED OPERAND
  if (typc>0x20)and(typc<0x40)and(typa<0x20)
    typc-=0x20 'SIGNED ACCUM
  elseif isfpu(typc) 'FLOAT ACCUM
    if typa<0x40
      return cpufpu(op,typa,wr)
    else
      goto nnumop
    endif
  elseif isfpu(typa) 'FLOAT OPERAND
    if op>1
      w1=cvtai(typc,0x68)
    endif
    typc=0x68  'UPGRADE ACCUM TO FLOAT
    goto nnumop
  endif
  '
  'CPU ONLY
  '
  d=op
  select op
  case 74,75,76,77 : typa=typc : d=1 'excluding shifts
  end select
  '
  if (d>1)and(c<4)and(a<4) 'SMALL OPERANDS
    w1=cvtai(typc,4)
    typc=4 : c=4 'UPGRADE ACCUM 'EG: ADDING BYTES
  elseif typa>typc 'UNSIGNED OR WIDER OPERANDS
    if a<=c 'UNSIGNED
      typc=cpuw : c=cpuw 'FULL ACCUM UPGRADE
    else 'a>c 'WIDER
      if d>1
        w1=cvtai(typc,typa) 'UPGRADE ACCUM
      endif
      typc=typa
      goto nnumop
    endif
  endif
  '
  if typc=typa
    goto nnumop 'MATCHED ACCUM AND OPERAND
  endif
  '
  'OPERAND CONVERSION
  if (d>1)and(typa<>typc) 'preconvert operand
    'opt direct load to ecx
    if (cpuw=8)and(typc=8)
      if typa=0x24
        return "mov ecx,"+wr+cr+operi(op,typc,qecx)
      elseif typa=0x04
        return "mov ecx,"+wr+cr+"movsxd rcx,ecx"+cr+operi(op,typc,qecx)
      endif
    endif
    'load operand to qecx
    string w4,w5,w6
    if c<8
      w5="ecx,"
    else
      w5="rcx,"
    endif
    int ta=asc(wr)
    w3="mov "
    if isn(ta)
      '
    else
      if a<c
        w4=identypes(typa)
        if (typa and 0x20)<>0
          w3="movzx "
        else
          w3="movsx "
        endif
      endif
    endif
    if c<cpuw
      w6="ecx"
    else
      w6=qecx
    endif
    return w1+w3+w4+w5+wr+cr+operi(op,typc,w6)
  endif 'op>1 and typa<>typc
  '
  nnumop:
  return w1+operi(op,typa,wr)+cvtai(typa,typc)
end function

 

'         ##################
'       #                  #
'       # ################## #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # ################## #
'        #                  #
'         ################## 
'
'
'
function compatsig(string*p1,*p2, int pb) as int 
================================================
  '
  ' p1 COMPOSED, p2 REQUIRED
  '
  int i1,i2,k,a,b,cprm,d,e,f,pa,m,n,nd,e1,e2,tg,tl,apa,oindt
  string s1,s2,w1,w2,w3,w4
  '
  oindt=indt
  if not p2
    return 1 'NO SIGNATURE
  endif
  if p2="@"
    p2=""    'NO PARAMS
  endif
  if len(p1)+len(p2)=0
    return 1 'NULL SIGNATURES
  endif
  '
  'SPLIT OFF INDIRECTION CODES
  '---------------------------
  '
  s1=splitsi(p1,wu1)
  s2=splitsi(p2,wu2)
  '
  'QTY OF PARAMS MISMATCH
  '----------------------
  '
  e1=len(wu1) : e2=len(wu2)
  '
  if e1<>e2
    a=1
    if e1<e2
      b=asc(wu2,e1+1) and 127
      if (b=46)or(b>64)
        a=0  'ALLOW ELLIPSIS OR OPTIONAL PARAMS
      endif
    elseif e1>e2
      if asc(wu2,e2)=46
        a=0  'ALLOW ELLIPSIS: '.'
      endif
    endif
    if a
      k=0 : exit function
    endif
  endif
  '
  'CHECK EACH PARAM
  '----------------
  '
  i1=1 : i2=1 : cprm=1
  dprm=0
  if cpuw=8
    aprm[1]=0
    aprm[2]=0
    aprm[3]=0
    aprm[4]=0
  endif
  do
    pa=cprm+pb 'itr direct UDT
    pet(pa)=pat(pa)
    w1=wordfrag(s1,i1)
    w2=wordfrag(s2,i2)
    '
    'COMPARE PARAM TYPES
    '-------------------
    '
    if len(w1)+len(w2)=0
      k=1 : exit do 'NO MORE PARAMS
    endif
    '
    '
    'INDIRECTION ELLIPSIS ETC
    '------------------------
    '
    d=asc(wu1,cprm) : e=asc(wu2,cprm)
    '
    stkb+=4 'FOR CDECL PARAMS
    '
    '
    if e>64
      e-=17 'DEFAULT PARAMS
      if w1=""
        typg=cpuw
        pas(pa)="mov "+qeax+cm+"0"+cr 'NULL DEFAULT
        pav(pa)=callcnv(cprm,qeax,e)
        goto nxtel
      endif
    endif
    '
    n=identype(w2) : e+=indt
    if cpuw=4
      if e<=48  
        if n=0x68
          stkb+=4 'FOR CDECL DOUBLE
        elseif n=0x6a
          stkb+=8 'FOR CDECL EXTENDED
        endif
      endif
    endif
    '
    m=identype(w1)
    '
    '
    'ELLIPSIS
    if e=46
      apa=1 '.' any param accepted
    endif
    if apa
      if isstr(m)
        if pao(pa)<=1
          dts--
          wg=paw(pa)
          a=typ
          typ=m
          makestrptr(wg)
          typ=a
          pas(pa)=wpfx
          typg=m
          pav(pa)=callcnv(cprm,wg,48)
        endif
      elseif m=0x68
        stkb+=4
      elseif m=0x6a
        stkb+=8
      endif
      if cpuw=8
        pet(pa)=8 'to use cpu regs instead of xmms
      endif
      goto nxtel
    endif
    '
    '
    'NULL OR BYVAL V, REQUIRING EXTRA STACK
    'exclude byval double or extended
    if d=95
      'ALLOW FLOAT CONVERSION
      if m>=typh
        if e>48
          goto nxtel
        endif
      else 'm<typh
        if pao(pa)=1024 'opg proc
          d=e
          m=n
        else
          if isfloat(n)=0
            n=cpuw
          endif
          if e>0
            n=cpuw
          endif
          d=48 : e=48
        endif
      endif
    endif
    '
    'd+=indt 'already pointered
    '
    '
    'GROUP COMPATIBILITY CHECKS
    '--------------------------
    '
    if n=m
      goto matchednm
    elseif (n=0x10)and(e>48)
      'VOID* TYPES TO BE SAME AS sys TYPE
      a=0
      if m<0
        if d>48
          a=1 : d-- : e-- : m=cpuw 'VOID* TO int
        endif
      elseif m=cpuw
        if d=48
          a=1 : e-- 'ALLOW BYVAL int TYPES TO BE TREATED LIKE VOID*
        endif
      elseif m>=typh
        if d>48
          a=1 : m=cpuw 'VOID* COMPATIBILITY
        endif
      endif
      if a
        n=cpuw 'TREAT AS int TYPES (HANDLES ETC) itr
      endif
    elseif (m<0x40)and(n<0x40)
      a=m and 15
      b=n and 15
      if b<a
        m=cpuw : n=cpuw 'NO UP CONVERSION CODE REQUIRED
      endif
    elseif n>=typh 'up-convert
      if uk and 2
        if findop(n,"conv",w1)
          'deferred object creation
          paj(pa)=n
          mpfx+=w1+"(#obj#,"+pex(pa)+cm+pat(pa)+")"+cr
          pas(pa)="lea "+qeax+cm+"#obj#"+cr
          pav(pa)=callcnv(cprm,qeax,e)
          k=2
          goto nxtel
        else
          k=0 : exit function
        endif
      endif
    elseif m>=typh
      if uk and 2
        if (d<=48)or(e<=48)
          k=0 : exit function
        endif
        'allow vectors to pass as floats etc
      endif
    endif
    '
    a=0
    '
    if w2="any"
      'always compatible (treat as int)
      n=m
    elseif w2="gstr_"
      if isdstr(m)
        a=1 'accept any bstring/dyn string width
      endif
    elseif w2="cstr_"
      if isstr(m)
        a=1 : 'accept any string width
      endif
    endif
    '
    if a
      n+=(m and 15) - (n and 15) 'ADJUST TO MATCH LENGTH
    else
      '
      'CONVERSION OF STRINGS WIDE<->ASCII
      '==================================
      '
      if isstr(n)
        a=m and 15
        b=n and 15
        if a<>b
          a=instrevn(-1,pas(pa),"|op 60 ")
          if a
            mid(pas(pa),a+8)=chr(48+b)
          endif
        endif
      endif
    endif
    '
    '
    '=========
    matchednm: 'CHECK FOR MATCHING TYPE
    '=========
    '
    if m=n
      k=1
    else
      k=2
    endif
    k and=uk                  'WHEN UK=1 A PERFECT MATCH IS REQUIRED
    if k=0
      exit function 'NOT COMPATIBLE
    endif
    '
    'pas(pa)     'DEFAULT PARAM EXPRESSION from wd
    'pav(pa)     'DEFAULT COMPATIBILITY CODE (usually push eax) from w1
    'pax(pa)     'INDIRECTION CODE from wpfx

    'PAS AND PAV ARE COMBINED TO MAKE THE FULL PARAM PASSING EXPRESSON
    '    
    wg=paw(pa)             'LAST OPERAND (translated)
    opg=pao(pa)            'LAST OPERATOR
    typg=pat(pa)           'ACCUM TYPE

    tg=typg and 0x7fffffe0 'ACCUM GENERIC TYPE
    tl=typg-tg             'ACCUM LENGTH
    '
    'PASSING UDT DIRECTLY ON STACK
    '
    if (cpuw=8) 'and(n<&x80) '(isfpu(n)<>0)
      if e>=49
        pet(pa)=cpuw 'pointer type
      else
        pet(pa)=n 'feedback for extern call regs
      endif
    endif
    '
    if (opg=1024)and(d>48)and(e=d)and(m=n)
      typg=cpuw
      pav(pa)=callcnv(cprm,qeax,e)
      goto nxtel 'PROC PARAM RETURNING POINTER
    endif
    '
    'OFFER CONVERSION CODE IF PERMITTED
    '==================================
    '
    w2="" : w3="" : convs=0
    '
    if (k and 6)>0
      '
      'CONVERSION CHECKS
      '
      if n=0x10
        n=m 'void* no conversion
      endif
      '
      if (uk and 4)=0
        if isstr(m)
          if isstr(n)=0
            k=0
          endif
        else
          if isstr(n)
            k=0
          endif
        endif
        if isdstr(n)
          if iszstra(m)
            k=0
          endif
        endif
        if k=0
          exit function
        endif
      endif
      '
      if m<>n
        w2=cvta(m,n)
      endif
      '
      if isstr(n)
        '
        'NUMBER TO STRING CONVERSION
        '
        '
        if isstr(m)=0
          if cpuw=8
            pet(pa)=n 'FEEDBACK CONVERSION
          endif
          if (e=48)and(iszstra(n)<>0)
            goto nxtel 'CHAR AS ASCII
          else
            pas(pa)+=w2+logas() : w2="" : convs=2 : d=48 'EARLY CONVERSION
          endif
        endif 'isstr(m)=0
        '
        'DIRECT ZSTRING / CHAR
        '
        if iszstra(n)
          if e=48 
            if (opg>1)or(convs<>0)
              pas(pa)+="mov "+qeax+cm+peax+cr : goto nxtel 'CHAR DIRECT (deref)
            endif
          endif
        endif 'isztr(n)
      endif 'isstr(n)
      '
      '
      m=n 
      typg=n
      '
      if cpuw=8
        int g=asc(wg)
        if (isq(g)<>0)or(opg>1)or(isstr(n)<>0)
          w1=qeax
        elseif (n>=0x40)and(n<0x80)
          w1=""
        elseif convs
          w1=qeax
        else
          w1=wg
        endif
        w3=w2+callcnv(cprm,w1,e)
      else 'NOT CPU=8
        w1=""
        w3=w2+operi(4,typg,w1) 'itr
      endif
      '
      if ert
        k=0 : exit function 'CONVERSION IMPOSSIBLE
      endif
      '
      pav(pa)=w3
    endif '(k and 6) >0 'CONVERSIONS
    '
    'FPU CALLING CONVENTION
    '======================
    '
    if (cco=17)or(n=0x40)
      pas(pa)+=w2
      pav(pa)=""
      goto nxtel
    endif
    '
    a=asc(wg)
    '
    '
    if d>48
      if convs
        d=48 'COMPEL TO USE TEMP STORAGE
      endif
    endif
    '
    '=======================
    'SHORTCUTS & INDIRECTION
    '=======================
    '
    if (opg<2)and(convs=0)
      '
      'HIGHER INDIRECTION
      if (e>=50)and(a=91)
        if (m=n) 'and(n<typh) 'and(isstr(m)<>0)
          w2=pax(pa)
          if isostr(m) 'o2 strings
            e-- 'reduce address trimming
          endif
          for a=50 to e
            if not refaddr(w2)
              'create temp ref vars instead
              w2=pax(pa)
              for a=50 to e
                w1=tmpvar()
                w2+="lea "+qeax+cm+wg+cr+operi(2,cpuw,w1)
                wg=w1
              next
              exit for
            endif
          next
          pas(pa)=w2+"lea "+qeax+cm+wg+cr
          pav(pa)=callcnv(cprm,qeax,e)
          goto nxtel

          'print pas(pa) cr d
          
          'if isostr(m)
          '  d=50
          'endif
          'if d<e-1
          '  ers="requires more indirection: arg "+str(cprm)
          '  ert=1000 : return -2
          'else
          '  pas(pa)=pax(pa)
          '  'if iszstra(m)
          '  '  d-- 'extra deref
          '  'endif
          '  for a=d+1 to e
          '    refaddr(pas(pa))
          '  next
          '  pas(pa)+="lea "+qeax+cm+wg+cr
          '  '
          '  if d>e
          '    a=len(pax(pa))+1
          '    mid(pas(pa),a)="mov"
          '  endif
          '  goto nxtel 'STRING ARRAY
          'endif
        endif
      endif
      '
      'STRINGS & CONSTANTS
      if isbstr(tg)
        b=asc(pax(pa))
        if b=hasa
          if left(pax(pa),4)="|qu "
            b=0x6f
          endif
        endif
        if b=0x6f 'O2..
          if iszstra(n)
            pas(pa)=pax(pa)
            if e=48
              pas(pa)+="mov "+qeax+cm+peax+cr 'CHAR DIRECT (deref)
            endif
            dts-- : goto nxtel
          else 'not zstring
            if e=48
              dts-- : pas(pa)=pax(pa) : goto nxtel
            endif
          endif
        endif
        if e=49
          if isbstr(n)
            if a=91 '[
              dts--
              pas(pa)=pax(pa)+"lea "+qeax+cm+wg+cr
              goto nxtel 'BSTRING ARRAY
            endif
          endif
        endif
      endif
      '
      '
      'BYREF
      '=====
      '
      if d>48
        if iszstra(m)
          if e=48
            pas(pa)=pax(pa)
            if wg<>qedi
              pas(pa)+=leaedi(wg)
            endif
            pav(pa)=callcnv(cprm,pedi,e)
            goto nxtel
          endif
        endif
        '
        'DOUBLE POINTERED (ONLY)
        '
        if e>d
          if not refaddr(pax(pa))
            k=1 : exit function
          endif
          d++
        endif
        '
        if (d=e)or(isstr(tg)<>0)
          goto varbref 'otherwise continue
        endif
      endif
    endif
    '
    '
    '==============
    'BYVAL TO BYVAL
    'BYREF TO BYVAL
    '==============
    '
    if d>=e
      '
      'INDIRECTION RESOLVED IN PWORD()
      '
      'SHORTCUTS
      '---------
      '
      'NUMBERS
      '
      if isn(a)
        if opg<2
          if d=e
            if typg<0x40
              if convs=0
                pas(pa)=""
                pav(pa)=callcnv(cprm,wg,e)
                goto nxtel
             endif
            endif
          endif
        endif
      endif
        
      if a=91
        '
        'VARIABLES
        'EXCLUDING BSTR
        '
        if (opg<2)and(convs=0)
          '
          'ELEMENTS AND MEMBERS BYVAL
          '
          if isstr(m)
            dts--
          endif
          '
          if (left(wg,4)=aedi)
            pas(pa)=pax(pa)
            if tg=0xe0
              pas(pa)+=medi+wg+cr : wg=pedi 'DEREFERENCE DYNAMIC STRING
            endif
            pav(pa)=callcnv(cprm,wg,e)
            goto nxtel
          endif
          '
          'TO BYPASS STRINGS CONCATENATORS
          '
          if tg=0xc0
            if d=e
              if iszstra(n)
                goto varbref
              endif
              pas(pa)=pax(pa) : pav(pa)=callcnv(cprm,wg,e) : goto nxtel 'direct
            endif
          elseif tg=0xe0
            goto varbref 'direct
          else
            '
            'if no conversion code / including floats
            '
            pas(pa)=pax(pa)
            pav(pa)=callcnv(cprm,wg,e)
          endif
        endif 'opg<2 and convs=0
      endif 'a=91
      '
      'if d>e
      'pas(pa) encoding takes care of dereferencing
      '
      goto nxtel
      '
    endif 'd>=e
    '
    '
    '--------------
    'BYVAL TO BYREF
    '==============
    '
    if d>=e
      goto nxtel
    endif
    '
    'PROVIDE TEMP STORAGE AND ADDRESS FOR EXPRESSION RESULT
    'PASS ADDRESS IF SIMPLE OR ARRAY ELEMENT
    '
    '
    if e=d+1
      '
      'BSTRING TO ZSTRING PTR
      '
      if (iszstra(tg)=0)and(iszstra(n)<>0)
        if convs
          pas(pa)+=cr+w2 : goto nxtel
        endif
        if opg>1
          goto nxtel
        endif
        goto varbref
      endif
    endif
    '
    '
    if typg>=typh
      goto nxtel 'ALLOW HIGHER TYPE TO PASS TO PRIMITIVE PARAM
    endif

    'GENERAL BYVAL TO BYREF
    '
    a=asc(wg)
    b=0
    '
    if opg>1  'EXPRESSIONS
      b=1
    elseif convs  'CONVERSIONS
      b=2
    endif
    '
    if isn(a) 'NUMBERS
      b=3
    elseif isq(a) 'QUOTES
      b=4
    elseif wg=qedi '@var etc
      b=5
      'w2=operi(1,cpuw,wg)
      convs or=1
      opg or=2048
    endif
    '
    'REQUIRING TEMP STORAGE
    '======================
    '
    'PRIMITIVES BYREF+
    if (e>=50)and(d=48)
      if n<typh
        w1=tmpvar()
        if isstr(n)
          n=cpuw
        endif
        w2=w2+operi(2,n,w1)+leaedi(w1)
        for a=50 to e
          w1=tmpvar()
          w2+="mov "+w1+cm+qedi+cr+leaedi(w1)
        next
        pav(pa)=w2+callcnv(cprm,qedi,e)
        'print "ptrd expresion" cr pas(pa) cr pav(pa)
        goto nxtel
      endif
    endif

    if b
      if convs=0
        convs=2
      endif
      if a=91 '[
        if opg<2
          goto varbref
        endif
      endif
    endif
    '
    'ARRAYS OR OTHER POINTER BYREF
    '
    if opg>1
      w1=tmpvar()
      if n>=0xa0
        n=cpuw 'STRINGS ACCUM
      endif
      pav(pa)=w2+operi(2,n,w1)+leaedi(w1)+callcnv(cprm,qedi,e)
      goto nxtel
    endif
    '
    'ARRAYS AND ELEMENTS BYREF
    '
    if left(wg,4)=aedi '[edi ...
      pas(pa)=pax(pa)
      if tg=0xe0 'OSTRINGS ONLY
        pav(pa)=strinit(pax(pa),wg,a)+callcnv(cprm,pecx,e) 'DEREF FOR STRINGS
      else
        pav(pa)=leaedi(wg)+callcnv(cprm,qedi,e)
      endif
      goto nxtel
    endif
    '
    '
    ========================
    varbref: 'VARIABLE BYREF
    ========================
    '
    '
    'REQUIRES TEMP STORAGE?
    '
    'BSTRING TO OSTRING
    if convs=0 
      if (isdstr(n)<>0)and(tg=0xc0)
        convs=2 'USE TEMP STRING
      endif
    endif
    '
    if (convs<>0)and(e>48)
      w1=tmpvar()
      if n>0xa0
        n=cpuw
      endif
      pav(pa)=w2+operi(2,n,w1)+leaedi(w1)+callcnv(cprm,qedi,e)
      goto nxtel
    endif
    '
    '
    if asc(wg)=91
      '
      if isstr(tg)
        if (iszstra(tg)=0)and(iszstra(n)<>0)
          'STRING TO CHAR*
          e-- 'ADJUST TO PASS POINTER DIRECTLY
        endif
      endif
      w1=""
      w3=wg
      if tg=0xe0
        'PASSING OSTRINGS
        'REREFERENCE SAFELY
        w1=strinit(pax(pa),wg,a) 'out a
        w3=pecx
        if e=49
          if a=0
            w1="" : w3=wg 'NO GC REGISTRATION
          endif
        else
          'DIRECT STRING
          for a=e to 48
            w1+="mov "+qecx+cm+pecx+cr 'DEREF [ecx]
            w3=pecx
          next
        endif
      else 'tg<>0xe0 'NOT PASSING OSTRING
        if e=48
          'PASS VALUE
        elseif e=47
          w1=medi+wg+cr
          w3=pedi 'DEREF FOR CHARACTER
        else
          w1=leaedi(wg) 'PASS ADDRESS
          w3=qedi
        endif
      endif
      '
      pas(pa)=pax(pa)
      pav(pa)=w1+callcnv(cprm,w3,e) 'itr w2
      goto nxtel
    endif
    '
    'fall thru
    '
    'ert=17 : ers="param compatibility problem "+wg
    '
    '===================
    nxtel: 'NEXT ELEMENT
    '===================
    '
    cprm++
    '
  loop
  '
  compatsx:
  '
  if k
    if apa=0
      pc=pc+(e2-e1) 'OPTIONAL PARAM FILL IN
    endif
  endif
  '
  indt=oindt
  return k
  '
end function


function extractoperand(string *s,*wr) as int
=============================================
  int a,b,c,op,typ,bg
  bg=instrevn(-1,s,"|")
  i=bg
  if i>=1
    if mid(s,i+1,2)="op" 'NOT 'go'
      i+=4
      op=hexval(s,i)
      typ=hexval(s,i)
      b=i
      c=instr(i,s,cr)
      if typ=15
        typ=cpuw
      endif
      wr=mid(s,b,c-b)
      s=left(s,bg-1) 'NO PRELOAD FOR LEFT SIDE
      return typ
    endif
  endif
end function
