

'----------------------------------
function enc(s as string) as string
'==================================
return "|"+s+cr
end function


'-------------------------------------
function rtl(byval p as sys) as string
'=====================================
  function=enc("go 0 "+memreg(qebx,p))
end function


'-------------------------------------
function deref(wr as string) as string
'=====================================
  function="mov "+wr+cm+"["+wr+"]"+cr
end function


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


'------------------------------------------------------------
function callcnvi(n as sys, wk as string, e as sys) as string
'============================================================
'pa
dim as sys ty=typg
if (ty>&ha0)or(e>48) then ty=cpuw
if vaf>8 then n+=1
return enc("pa "+hexci(n)+" "+hexci(cco)+" "+hexci(ty)+" "+rtrim(wk))
end function
'

'-----------------------------------------------------------------------
function operi(byval qp as sys, byval tp as sys, wk as string) as string
'=======================================================================
'op
'
if qp=0 then qp=1
if (cpoint)and(ind) then
  if qp=12 then return "add "+wk+cm+str(lent)+cr '++
  if qp=13 then return "sub "+wk+cm+str(lent)+cr '--
end if
if isstr(tp) then
  lcl=1
  select case qp
  case 1  : jn=nst+1
  case 33 : jn=nst+1
  case 43 : jn=nst+1
  case 45 : jn=nst+1
  case 2  : jn=0
          if isbstr(tp) then
            if left(wk,5)="[ebp+" then
              if instr(8,wk,"-")=0 then
                ert=1004
                ers="Must not assign to a direct string param"
              end if
            end if
          end if
  case 96 : jn=0 : dcs=1
            if funi then lcl=1 ' lcl for cat buf
  end select
end if
return enc("op "+hexci(qp)+" "+hexci(tp)+" "+wk)
end function


'---------------------------------------------
sub indiri(byref wr as string, byval n as sys)
'=============================================
if n then
  wpfx+=medi+wr+cr
  n-=1
  if n then wpfx+=repeat(medi+pedi+cr,n)
end if
end sub
'

'------------------------------------------------
function cvtai(typa as sys,typb as sys) as string
'================================================
'cv
dtf=0 
if typa<>typb then
  return enc("cv "+hexci(typa)+" "+hexci(typb))
end if
end function


'-------------------------
function logas() as string
'=========================
  if dts<0 then
    dts=1
  else
    dts+=1
  end if
  if funi then lcl=1 : lcls=1
  function=rtl(asstmpa) 'LOG FOR DELETION
end function


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


'-----------------------------
sub addrtrim(byref s as string)
'==============================
  dim as sys a
  dim as string w1
  a=instrevn(-1,s,medi)
  if a then
    w1=mid(s,a)
    if instr(w1,medi+pedi) then
      w1=""
    else
       mid(w1,1)="lea"
       'RETURN ADDRESS ONLY
    end if
    s=left(s,a-1)+w1  'REMOVE ONE LEVEL FROM RIGHT
  else
    ert=18 : ers="unable to get address"
  end if
end sub


'---------------------------------
sub extractadr(byref wr as string)
'=================================
  dim as sys a,b
  a=instrevn(-1,wpfx,medi)
  if a then
    b=instr(a,wpfx,"]"+cr)
    if b then
      'len(med)=8
      a+=8 : b+=1
      wr=mid(wpfx,a,b-a)
      wpfx=left(wpfx,a-9)
    end if
  elseif instr(wpfx,qedi) then 'itr members
    wr=qedi
  else
    ert=725
    ers="unable to extract address"
  end if
end sub


'----------------------------------------------
sub varadr(byref wr as string, byref da as sys)
'==============================================
  if wr=pedi then
    if len(wpfx) then
      if da then  ' @@ &&
        da=0
        addrtrim(wpfx) 'DEPOINTER
      end if
      extractadr(wr)
    else 'no wpfx
      wr=qedi
    end if
  else 'wr<>pedi
    wpfx+=leaedi(wr)
    wr=qedi
  end if
  typ=cpuw
  varf=1
end sub


'---------------------------------
sub makestrptr(byref wr as string)
'=================================
  dim as string w2
  dim as sys a
  ascw=asc(wr)
  if isq(ascw) then
    wpfx=enc("qu "+wr)
    wr=qeax : goto nmakestr
  elseif isn(ascw) then
    goto nmakestr
  elseif wr="null" then
    wr="0"
    goto nmakestr
  elseif (typ<&h40) then
    wpfx+="mov "+qedi+cm+wr+cr
  elseif (typ<&h80) then
    wpfx+=operi(1,typ,wr)+_
    "sub rsp,8"+cr+"fstp qword [rsp]"+cr+"mov rdi,[rsp]"+cr+"add rsp,8"+cr
  elseif (typ<&hc0) then
    wpfx+="lea "+qedi+cm+wr+cr
  elseif typ>&he0 then
    'CHECK FOR NULL DYNAMIC STRING
    wpfx+="mov "+qedi+cm+wr+cr+"cmp "+qedi+",0"+cr+_
    "jz fwd ndr"+cr+"mov "+qedi+cm+pedi+cr+".ndr"+cr
  elseif typ<&he0 then
    goto nmakestr
  end if
  '
  wr=qedi
  '
  nmakestr:
  '
  typ=cpuw
  wpfx="._direct_"+cr+wpfx
end sub

'---------------------------------------------------
function makestrptrfun(byref wr as string) as string
'===================================================
dim as string wt
makestrptr(wr)
wt=wpfx
if wr<>qeax then
  wt+="mov "+qeax+cm+wr+cr
  wr=qeax
end if
return wt
end function


'---------------------------
function returns() as string
'===========================
  '
  'BYTES TO DISCARD FROM STACK WHEN RETURNING
  '------------------------------------------
  '
  dim as sys a=reto
  dim as sys b=ccp       'CALLING CONVENTION
  maco(mqf,1)=a          'LENGTH OF PARAMS
    '
    'APPLIES TO STDCALL AND PASCAL ONLY
    '
    if (b=0)or(b=8) then
      if a then
        return "ret "+str(a)+cr 'but not with ellipsis (auto cdecl)
      end if
    end if
    return "ret"+cr
end function


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



'-----------------------------------------------------------------------------
sub replaceregs(byref s as string,b as sys,e as sys,r1 as string,r2 as string)
'=============================================================================
dim as sys a
a=b
do
  a=instr(a,s,r1)
  if (a=0)or(a>e) then exit do
  mid(s,a)=r2
  a+=3
loop
end sub


'-----------------------------------------------------
sub setthis(w1 as string, byref a as sys)
'=====================================================
  dim as string w2
  ths=mest
  '
   vars(w1+" this at "+memreg(qebp,a)+cr)
   a+=cpuw
   lcl=1
  '
end sub


'-------------------------------------
sub prepforlocalspace(byval pn as sys)
'=====================================
  dim as sys a,i
  dim as string w1,w3
  '
  asce=-1
  aoffl=-cpuw*3  'allow for string lists
  aoff=aoffl
  blcl=j 'PATCH POSITION FOR STACK INSTRUCTION
  w1=savestack
  '
  '
  if cpuw=8 then
  '
  '
    'STORE REG PARAMS ONTO STACK
    '
    'but only necessary for external procs
    '
    a=16
    '
    if atf then
      a=48
      w1+=memregspill(a,pn) 'SPILL REG PARAMS IN 64 BIT MODE
    end if
  end if
  '
  appendt(w1)
  plcl=j 'PATCH POSITION FOR STACK ALLOCATION
  appendt(enc("sp -64"+space(5)))
  '
  '
  a=0
  '
  'RETURNED VARIABLE
  '
  if (wva(1)<>"")and(ccp<>17) then
    '
    a=typp
    w3=" _retval"
    '
    if a<htyp then
      if a=&h40 then a=&h68 : wva(1)="double" 'fpu return type using qword slot
      a and=31
    end if
    '
    'c=cef : cef=0 'no emit
    vars(wva(1)+w3)
    'cef=c
    '
  end if '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 then
    if (a=24)or(a=40) then a+=8 : aoff-=8 : aoffl=aoff
  end if
  '
  if a>0 then
    roundup(a,cpuw)
  end if
  mlcl=a
  appendt(enc("si            " )) 'STACK FRAME INIT TO ZEROS
  'appendt(enc("si "+hexci(a)+space(8) )) 'STACK FRAME INIT TO ZEROS
  'appendt(enc("sx ")) 'MARKER
  '
end sub


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


'-------------------------------------------------------------------------------
sub multiassigna(byref wt as string, byref w1 as string, wr as string, a as sys)
'===============================================================================
  if a then
    a=instrevn(len(wt)-2,wt,cr)
    if a then
      w1+=left(wt,a+1)
    end if
    wt=w1+"mov "+identypes(typ)+memreg(qedi,asgo)+cm+wr+cr 'INTEGER NUMBERS
  else
    wt+=w1+operi(2,typ,memreg(qedi,asgo))
    if (typ>=&he0)and(typ<&h100) then
      if asgl then a=asstrla else a=asstrga
      wt+=rtlo(a) 'STRING ASSIGNMENT WITH GC
    end if
  end if
end sub


'-----------------------------------------------------
sub noprototype(byref wd as string,byref w1 as string)
'=====================================================
  if asc(wg)=41 then
    'wd whole expression
    w1=""
  else
    wd=wpfx
    w1=wg
  end if
  if (nan=0)or(isfloat(typg)) then
    wd=""
    if typk=0 then
      if isfloat(typg) then
        typg=&h64 'assume single precis num literals
      end if
    end if
  elseif isstr(typg)or(wg=qedi) then
    typg=cpuw
  elseif (typg>=htyp)and(bvg=0) then 'bvg: null flag
    'passing direct higher types: rect etc
    if wpfx="" then
      wd=leaedi(wg) : w1=qedi : typg=cpuw
    else  'wpfx
      if (wg=pedi)and(maco(mp,3)=1) then 'simple indirection level 1
        wd=""
        w1=macso(mp,1)
      else
        if wg<>pedi then 'array offsets etc
          wd+=leaedi(wg)
        end if
        w1=qedi
      end if
    end if
    typg=cpuw
  end if
end sub


'--------------------------------------------------------
function  buildparamblock(pb as sys, cc as sys) as string
'========================================================
  dim as sys a,b,c,d,k,l,m,n,p,q,r11
  dim as string w1,w2,w3,w4
  '
  a=pc : b=pb+1 : c=-1
  '
  '
  'PARAMETER ORDER 0..7 REVERSE,  8.. FORWARD
  '
  if cc>=8 then swap a,b : c=1 'LEFT TO RIGHT STACKING
  '
  if cc=2 then
    if varf>8 then k=1
    for d=a to b step c
      m=1
      w3=pas(d)+pav(d)
      q=d-b+k+1
      n=pat(d) and 15
      if (isfloat(pat(d))=0)and(q<5) then m=2
      if instr(w3,"|go 0 ") then
        w2=w1 : p=0 'prev volatile regs no longer safe
      elseif q=1 then
        if instr(w3,"|op 2A ")+instr(w3,"|op 2F ")+instr(w3,"|op 5C ") then
          w1+="mov r11,rdx"+cr : r11=1 'protect rdx when multiplying or dividing
        end if
      end if
      w1+=w3
      if pat(d)=&h40 then m=1
      'if n<8 then m=3
      if m=1 then 'HOLD ON STACK
        w2+=w3
      else 'm=2 'DIRECT LOAD TO REGISTER
        if p<q then p=q 'highest unused reg
        n=len(w3)
        a=instrevn(-1,w3," ")
        if n-a<=2 then w4=cr else w4=mid(w3,a+1)
        m=len(rgp(q))
        n=instrevn(a,w3,"|pa ")
        w2+=left(w3,n-1)+"|pb "+str(q)+" "+w4
      end if
      pav(d)=""
      if r11 then
        w1+="mov rdx,r11"+cr : r11=0
      end if
    next
  else
    for d=a to b step c
      w1+=pas(d)+pav(d)
      pav(d)=""
    next
  end if
  '
  if p then w4=w2 else w4=w1
  w1=""
  '
  if (cc=2)or(cc=3) then
    '
    a=pc-pb
    '
    'LOAD STACKED PARAMS INTO REGISTERS
    '
    if (a>0)and(cc=2) then
      c=1
      d=a
      if varf>8 then c+=1 : d+=1 'OOP params
      if d>4 then d=4
      '
      w1=hexci(c)+" "+hexci(p)+" "
      for b=c to d
        w1+=hexci(pat(pb+b))+" "
      next
      w1=regparams(w1,1)+cr
    end if  
    '
    'DETERMINE REQUIRED STACKSPACE
    '
    if a<7 then a=7
    'round up to nearest 16
    'min 64
    asm
    mov eax,[a]
    shr eax,1
    shl eax,4
    add eax,16
    mov [tmpstk],eax
    end asm
  end if
  function=w4+w1
end function


'----------------------------------------------------------------------------------------------
function preparecall(byval wp as string, byref w4 as string, wm as string, cc as sys) as string
'==============================================================================================
  dim as string w1,w3,w5
  dim as sys a,b,d,v
  '
  'FUNCTION CALL
  '
  if varf<=8 then
    a=asc(w4)
    if a=91 then
      w3=""
    else
      if asc(pls)=48 then
        w3=", "
      else
        w3=pls+" "
      end if
      a=lookupm(wp)
      if nsp then
        w4=wm 'NAMESPACE PREFIX + NAME + SIGNATURE
      end if
      w4+=" "+hexci(nsi)+" "+hexci(nsp)
    end if
    function=enc("go 0 "+w3+w4)
    exit function
  end if
  '
  'METHOD CALL
  '
  d=maco(mq,2) 'INTERNAL FUNCTION TABLE INDEX
  v=maco(mq,3) 'VIRTUAL MODALITY
  '
  if v>1 then 'VIRTUAL / PURE  CLASS 
    d=0 ' MUST USE EXTERNAL TABLE
  end if
  '
  w5=memreg(regst,toff+woff)
  '
  if w4=w5 then goto necxadjust
  '
  a=varf-10 : if a<0 then a=0 'TO ADD MULTI-INHERIT OFFSET
  w3="lea "+qecx+cm+memregadj(w4,a)+cr 'LOAD OBJECT ADDRESS
  '
  if v>1 then
    'VIRTUAL TABLE POINTER IS USED TO GET METHOD
    w3+=operi(1,cpuw,pecx) 'LOAD VIRTUAL TABLE ADDRESS
  elseif v then
    'VIRTUAL TABLE POINTER IS INCLUDED IN OBJECT
    if vtq then
      'INHERITED METHOD EXPECTS VTP OFFSET
    else
      'INHERITED METHOD EXPECTS NO VTP OFFSET
      w3+="add "+qecx+cm+str(cpuw)+cr
    end if
  end if
  '
  necxadjust:
  '
  'INTERNAL OR EXTERNAL VFT
  '
  if d=0 then 'NO INTERNAL FUNCTION TABLE
    if v=0 then ert=302 : ers="Class must be EXTERNAL/COM"
    w5=memreg(cpua,woff) 'VIRTUAL FUNCTION ADDRESS
  end if
  '
  'COMPOSE THE CALL INCLUDING 'THIS' IN THE ECX REGISTER
  '
  if asc(pls)=48 then
    pls=","+macso(maco(mp,0)-htyp,0)+"."+wm 'FWD REF REQUIRES NAMED CLASS.PROCEDURE
  end if
  '
  w5=pls+" "+w5+" "+hexci(nsi)+" "+hexci(nsp)
  '
  if (cc=2)or(cc=3) then
    function=w3+"mov [rsp],rcx"+cr+"|go 4 "+w5+cr
  elseif (cc=16)or(cc=17) then
    function=w3+enc("go 4 "+w5) 'fastcall
  else
    function=w3+operi(4,cpuw,qecx)+enc("go 4 "+w5)
    stkb+=4
  end if
end function


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


'------------------------------
sub checkstringparam(ty as sys)
'==============================
if isbstr(ty) then
  dim as sys a
  dim as string w2="["+qebp+"+"
  a=instrevn(-1,asg,w2)
  if a then
    a=instr(a,asg,"]")
    a+=1
    if asc(asg,a)=44 then
      ert=156 : ers="Must not assign to a string param passed byval "
    end if
  end if
end if
end sub


'----------------------------
function retvalue() as string
'============================
  dim as sys b
  dim as sys a=typp
  dim as string w1,w2
  if (lcl=0)or(ccp=17) then exit function
  b=lookupm("_retval")
  if b=0 then exit function 'SUB
  w2=macso(b,1)
  if w2=qeax then exit function
  '
  'ENCODE FOR RETURNING DIFFERENT TYPES
  '
  if a<&h80 then
    '
    if cpuw=8 then
      if a>=&h60 then
        if atf then
          'itr any type conversion?
          a and=31
          w1="movss xmm0,"+w2+cr
          if a>=8 then mid(w1,5)="d" 'double: "movsd"
          function=w1 : exit function
        end if
      end if
    end if
    if a=&h40 then a=&h68 'fpu type assumes double type here
    w1=operi(1,a,w2) 'RETURN INTEGERS AND FLOATS
    if cpuw=4 then
      if (a>=40)and(a<&h4f) then
        w1="mov eax,"+w2+cr+"mov edx,"+memregadj(w2,4)+cr
      end if    
    end if
    '
  elseif (a>=&he0)and(a<&h100) then
    w1=medi+w2+cr+rtl(trbstra)  'RETURN STRINGS
  else
    w1=operi(1,cpuw,w2) 'DEFAULT RETURN FOR BSTRINGS / HIGHER TYPES / POINTERS
  end if
  '
  function=w1
  '
end function


'------------------------------------
function lazyJump(d as sys) as string
'====================================
dim as sys f=1
if (d=33)or(d=71) then
  'IF (A)AND(B) THEN ... always fail
  function=boolcnd+"jz fwd _cnd"+cr
  f=0
elseif (d=34)or(d=72) then
  'IF (A)OR(B) THEN .. always succeed
  function=boolcnd+"jnz fwd _cnd"+cr
  f=0
end if
if (cnd or f)=0 then ppfx="._cnd"+cr
end function


'----------------------------------------------------------------------------
function numoperation(wr as string, typa as sys, byref typc as sys) as string
'============================================================================
  'supports numeric conversions
  dim as string w1,w2
  dim as sys a,c,cn
  cn=ascn
  if typc=0 then
    if typa<&h40 then
      typc=(typa and &hfffffff0)+cpuw 'determine signed or unsigned
    else
      typc=typa
    end if
  end if
  if (typc>&h20)and(typc<&h40)and(typa<&h20) then
    typc-=32 'SIGNED ACCUM
  elseif isfpu(typc) then
    if typa<&h40 then
      'function=cpufpu(op,typa,wr)
      function=enc("fp "+hexci(op)+" "+hexci(typa)+" "+wr)
      exit function
    else
      goto nnumop
    end if
  elseif isfpu(typa) then
    if op>1 then w1=cvtai(typc,&h68)
    typc=&h68  'UPGRADE ACCUM TO FLOAT
    goto nnumop
  end if
  'CPU ONLY
  if typa>typc then
    a=typa and 15
    c=typc and 15
    if a<=c then
      typc=cpuw 'convert to signed cpu type
    else
      if op>1 then w1=cvtai(typc,typa)
      typc=typa
      goto nnumop
    end if
  end if
  if typc=typa then goto nnumop
  w2=cvtai(typa,typc)
  if len(w2) then
    if op>1 then
      w1=operi(2,cpuw,qecx)+operi(1,typa,wr)+w2+operi(10,cpuw,qecx)
      wr=qecx
      typa=typc
      w2=""
    end if
  end if
  nnumop:
  function=w1+operi(op,typa,wr)+w2
  ascn=cn
end function



'         ##################
'       #                  #
'       # ################## #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # #                # #
'       # ################## #
'        #                  #
'         ################## 
'
'
'
'---------------------------------------------------------------------------------
function compatsig(byref p1 as string, byref p2 as string, byval pb as sys) as sys 
'=================================================================================
  '
  ' p1 COMPOSED, p2 REQUIRED
  '
  dim as sys i1,i2,k,a,b,c,d,e,f,pa,m,n,nd,e1,e2,tg,tl,apa,oindt
  dim as string s1,s2,w1,w2,w3,w4
  '
  oindt=indt
  if p2="" then return 1  'NO SIGNATURE
  if p2="@" then p2=""    'NO PARAMS
  if len(p1)+len(p2)=0 then return 1 'NULL SIGNATURES
  '
  '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 then
    a=1
    if e1<e2 then
      b=asc(wu2,e1+1) and 127
      if (b=46)or(b>64) then a=0  'ALLOW ELLIPSIS OR OPTIONAL PARAMS
    elseif e1>e2 then
      if asc(wu2,e2)=46 then a=0  'ALLOW ELLIPSIS: '.'
    end if
    if a then
      k=0 : exit function
    end if
  end if
  '
  'CHECK EACH PARAM
  '----------------
  '
  i1=1 : i2=1 : c=1
  do
    pa=c+pb
    w1=wordfrag(s1,i1)
    w2=wordfrag(s2,i2)
    '
    'COMPARE PARAM TYPES
    '-------------------
    '
    if len(w1)+len(w2)=0 then
      k=1 : exit do 'NO MORE PARAMS
    end if
    '
    '
    'INDIRECTION ELLIPSIS ETC
    '------------------------
    '
    d=asc(wu1,c) : e=asc(wu2,c)
    '
    stkb+=4 'FOR CDECL PARAMS
    '
    '
    if e>64 then
      e-=17 'DEFAULT PARAMS
      if w1="" then
        typg=cpuw
        pas(pa)="mov "+qeax+cm+"0"+cr 'NULL DEFAULT
        pav(pa)=callcnvi(c,qeax,e)
        goto nxtel
      end if
    end if
    '
    n=identype(w2) : e+=indt
    if cpuw=4 then
      if e<=48 then  
        if n=&h68 then
          stkb+=4 'FOR CDECL DOUBLE
        elseif n=&h6a then
          stkb+=8 'FOR CDECL EXTENDED
        end if
      end if
    end if
    '
    m=identype(w1)
    '
    'ELLIPSIS
    if e=46 then apa=1 '.' any param accepted
    if apa then
      if isstr(m) then
        if pao(pa)<=1 then
          dts-=1
          wg=paw(pa)
          a=typ
          typ=m
          makestrptr(wg)
          typ=a
          pas(pa)=wpfx
          pav(pa)="push "+wg+cr
        end if
      elseif m=&h68 then
        stkb+=4
      elseif m=&h6a then
        stkb+=8
      end if
      goto nxtel
    end if
    '
    'NULL OR BYVAL V, REQUIRING EXTRA STACK
    'exclude byval double or extended
    if d=95 then
      if m>=htyp then goto nxtel
      'ALLOW FLOAT CONVERSION
      if e>0 then n=cpuw
      if isfloat(n)=0 then n=cpuw
      d=48 : e=48
    end if
    '
    'd+=indt 'already pointered
    '
    '
    'GROUP COMPATIBILITY CHECKS
    '--------------------------
    '
    if n=m then
      goto matchednm
    elseif (n<0)and(e>48) then
      'VOID* TYPES TO BE SAME AS SYS TYPE
      a=0
      if m<0 then
        if d>48 then a=1 : d-=1 : e-=1 : m=cpuw 'VOID* TO SYS
      elseif m=cpuw then
        if d=48 then a=1 : e-=1 'ALLOW BYVAL SYS TYPES TO BE TREATED LIKE VOID*
      elseif m>=htyp then
        if d>48 then a=1 : m=cpuw 'VOID* COMPATIBILITY
      end if
      if a then n=cpuw 'TREAT AS SYS TYPES (HANDLES ETC) itr
    elseif (m<&h40)and(n<&h40) then
      a=m and 31
      b=n and 31
      if b<a then
        m=cpuw : n=cpuw 'NO UP CONVERSION CODE REQUIRED
      end if
    elseif n>=htyp then
      if m<>n then
        if (m>=htyp)or(n>=htyp) then
          exit function 'HIGHER TYPES MISMATCH
        end if
      end if
    end if
    '
    a=0
    '
    if w2="any" then
      'always compatible (treat as sys)
      n=m
    elseif w2="gstr_" then
      if isdstr(m) then a=1 : 'accept any bstring/dyn string width
    elseif w2="cstr_" then
      if isstr(m) then a=1 : 'accept any string width
    end if
    '
    if a then
      n+=(m and 31) - (n and 31) 'ADJUST TO MATCH LENGTH
    else
      '
      'CONVERSION OF STRINGS WIDE<->ASCII
      '==================================
      '
      if isstr(n) then
        a=m and 31
        b=n and 31
        if a<>b then
          a=instrevn(-1,pas(pa),"|op 60 ")
          if a then
            mid(pas(pa),a+8)=chr(48+b)
          end if
        end if
      end if
    end if
    '
    '
    '=========
    matchednm: 'CHECK FOR MATCHING TYPE
    '=========
    '
    if m=n then k=1 else k=2
    k and=uk                  'WHEN UK=1 A PERFECT MATCH IS REQUIRED
    if k=0 then exit function 'NOT COMPATIBLE
    '
    '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 &h7fffffe0 'ACCUM GENERIC TYPE
    tl=typg-tg             'ACCUM LENGTH
    '
    '
    '
    'FLOATS IN 64BIT MODE
    '
    if (cpuw=8) and(isfpu(n)) then
      if e>=49 then
        pat(pa)=cpuw 'pointer type
      else
        pat(pa)=n 'feedback: floats may use simd registers
      end if
    end if
    '
    '
    '
    'OFFER CONVERSION CODE IF PERMITTED
    '==================================
    '
    w2="" : w3="" : convs=0
    '
    if (k and 6)>0 then
      '
      'CONVERSION CHECKS
      '
      if n=-1 then n=m 'void* no conversion
      '
      if (uk and 4)=0 then
        if isstr(m) then
          if isstr(n)=0 then k=0
        else
          if isstr(n) then k=0
        end if
        if isdstr(n) then
          if iszstr(m) then k=0
        end if
        if k=0 then exit function
      end if
      '
      if m<>n then
        w2=cvta(m,n)
      end if
      '
      if isstr(n) then
        '
        'NUMBER TO STRING CONVERSION
        '
        '
        if isstr(m)=0 then
          if cpuw=8 then pat(pa)=n 'FEEDBACK CONVERSION
          if (e=48)and(iszstr(n)<>0) then
            goto nxtel 'CHAR AS ASCII
          else
            pas(pa)+=w2+logas() : w2="" : convs=2 : d=48 'EARLY CONVERSION
          end if
        end if 'isstr(m)=0
        '
        'DIRECT ZSTRING / CHAR
        '
        if iszstr(n) then
          if e=48 then 
            if (opg>1)or(convs) then
              pas(pa)+="mov "+qeax+cm+peax+cr : goto nxtel 'CHAR DIRECT (deref)
            end if
          end if
        end if 'isztr(n)
      end if 'isstr(n)
      '
      '
      m=n 
      typg=n
      '
      if cpuw=8 then
        if isq(asc(wg))or(opg>1)or(isstr(n)<>0) then
          w1=qeax
        elseif (n>=&h40)and(n<&h80) then
          w1=""
        elseif convs then
          w1=qeax
        else
          w1=wg
        end if
        w3=w2+callcnvi(c,w1,e)
      else 'NOT CPU=8
        w3=w2+operi(4,typg,"") 'itr
      end if
      '
      if ert then k=0 : exit function 'CONVERSION IMPOSSIBLE
      '
      '
      pav(pa)=w3
    end if '(k and 6) >0 'CONVERSIONS
    '
    'FPU CALLING CONVENTION
    '======================
    '
    if (cco=17)or(n=&h40) then
      pas(pa)+=w2
      pav(pa)=""
      goto nxtel
    end if
    '
    a=asc(wg)
    '
    '
    if d>48 then
      if convs then d=48 'COMPEL TO USE TEMP STORAGE
    end if
    '
    '=======================
    'SHORTCUTS & INDIRECTION
    '=======================
    '
    if (opg<2)and(convs=0) then
      '
      'HIGHER INDIRECTION
      if e>=50 then
        if (m=n)and(isstr(m)) then
          if isostr(m) then d=50
          if d<e-1 then
            ers="requires more indirection: arg "+str(c)
            ert=1000 : return -2
          else
            pas(pa)=pax(pa)
            'if iszstr(m) then d-=1 'extra deref
            for a=d+1 to e
              addrtrim(pas(pa))
            next
            pas(pa)+="lea "+qeax+cm+wg+cr
            '
            if d>e then
              a=len(pax(pa))+1
              mid(pas(pa),a)="mov"
            end if
            goto nxtel 'STRING ARRAY
          end if
        end if
      end if
      '
      'STRINGS & STRING CONSTANTS
      if isbstr(tg) then
        b=asc(pax(pa))
        if b=hasa then
          if left(pax(pa),4)="|qu " then b=&h6f
        end if
        if b=&h6f then 'O2..
          if iszstr(n) then
            pas(pa)=pax(pa)
            if e=48 then
              pas(pa)+="mov "+qeax+cm+peax+cr 'CHAR DIRECT (deref)
            end if
            goto nxtel
          else 'not zstring
            if e=48 then
              pas(pa)=pax(pa) : goto nxtel
            end if
          end if
        end if
        if e=49 then
          if isbstr(n) then
            pas(pa)=pax(pa)+"lea "+qeax+cm+wg+cr : goto nxtel 'BSTRING ARRAY
          end if
        end if
      end if 'isbstr
      '
      '
      'BYREF
      '=====
      '
      if d>48 then
        if iszstr(m) then
          if e=48 then
            pas(pa)=pax(pa)
            if wg<>qedi then pas(pa)+=leaedi(wg)
            pav(pa)=callcnvi(c,pedi,e)
            goto nxtel
          end if
        end if
        '
        'DOUBLE POINTERED (ONLY)
        '
        if e>d then
          addrtrim(pax(pa))
          if ert then k=1 : exit function
          d+=1
        end if
        '
        if (d=e)or(isstr(tg)) then
          goto varbref 'otherwise continue
        end if
      end if
    end if
    '
    '
    '==============
    'BYVAL TO BYVAL
    'BYREF TO BYVAL
    '==============
    '
    if d>=e then
      '
      'INDIRECTION RESOLVED IN PWORD()
      '
      'SHORTCUTS
      '---------
      '
      'NUMBERS
      '
      if isn(a) then
        if opg<2 then
          if d=e then
            if typg<&h40 then
              if convs=0 then
                pas(pa)=""
                pav(pa)=callcnvi(c,wg,e)
                goto nxtel
             end if
            end if
          end if
        end if
      end if
        
      if a=91 then
        '
        'VARIABLES
        '
        if (opg<2)and(convs=0) then
          '
          'ELEMENTS AND MEMBERS BYVAL
          '
          if (left(wg,4)="["+qedi) then
            pas(pa)=pax(pa)
            if tg=&he0 then
              pas(pa)+=medi+wg+cr : wg=pedi 'DEREFERENCE DYNAMIC STRING
            end if
            pav(pa)=callcnvi(c,wg,e)
            goto nxtel
          end if
          '
          'TO BYPASS STRINGS CONCATENATORS
          '
          if tg=&hc0 then
            if d=e then
              if iszstr(n) then goto varbref
              pas(pa)=pax(pa) : pav(pa)=callcnvi(c,wg,e) : goto nxtel 'direct
            end if
          elseif tg=&he0 then
            goto varbref 'direct
          else
            '
            'if no conversion code / including floats
            '
            pas(pa)=pax(pa)
            pav(pa)=callcnvi(c,wg,e)
          end if
        end if 'opg<2 and convs=0
      end if 'a=91
      '
      'if d>e then pas(pa) encoding takes care of dereferencing
      '
      goto nxtel
      '
    end if 'd>=e
    '
    '
    '--------------
    'BYVAL TO BYREF
    '==============
    '
    if d<e then
      'PROVIDE TEMP STORAGE AND ADDRESS FOR EXPRESSION RESULT
      'PASS ADDRESS IF SIMPLE OR ARRAY ELEMENT
      '
      '
      if e=d+1 then
        '
        'BSTRING TO ZSTRING PTR
        '
        if (iszstr(tg)=0)and(iszstr(n)<>0) then
          if convs then pas(pa)+=cr+w2 : goto nxtel
          if opg>1 then goto nxtel
          goto varbref
        end if
      end if
      '
      '
      'GENERAL BYREF
      '=============
      '
      a=asc(wg)
      b=0
      '
      if typg>=htyp then
        goto nxtel 'ALLOW HIGHER TYPE TO PASS TO PRIMITIVE PARAM
      elseif opg>1 then
        b=1
      elseif convs then
        b=2
      elseif isn(a) then
        b=3
      elseif isq(a) then
        b=4
      elseif wg=qedi then
        b=5
        w2=operi(1,cpuw,wg)
        convs or=1
      end if
      '
      'REQUIRING TEMP STORAGE
      '======================
      '
      if b then
        if convs=0 then convs=2
        if opg<2 then goto varbref
      end if
      '
      '
      'ARRAYS OR OTHER POINTER BYREF
      '
      if opg>1 then
        if n>=&ha0 then n=cpuw
        w1=tmpvar()
        pav(pa)=w2+operi(2,n,w1)+leaedi(w1)+callcnvi(c,qedi,e)
        goto nxtel
      end if
      '
      'ARRAYS AND ELEMENTS BYREF
      '
      if left(wg,4)="["+qedi then
        pas(pa)=pax(pa)
        if tg=&he0 then
          pav(pa)=strinit(pax(pa),wg)+callcnvi(c,pecx,e) 'DEREF FOR STRINGS
        else
          pav(pa)=leaedi(wg)+callcnvi(c,qedi,e)
        end if
        goto nxtel
      end if
      '
      '
      '=======================
      varbref: 'VARIABLE BYREF
      '=======================
      '
      '
      'REQUIRES TEMP STORAGE?
      '
      if convs=0 then 
        if (isdstr(n)<>0)and(tg=&hc0) then convs=2 'USE TEMP STRING
      end if
      '
      if (convs)and(e>48) then
        w1=tmpvar()
        if n>&ha0 then n=cpuw
        pav(pa)=w2+operi(2,n,w1)+leaedi(w1)+callcnvi(c,qedi,e)
        goto nxtel
      end if
      '
      '
      if asc(wg)=91 then
        w1=""
        if isstr(tg) then
          if (iszstr(tg)=0)and(iszstr(n)<>0) then
            e-=1 'ADJUST TO PASS POINTER DIRECTLY
          end if
        end if
        '
        if tg=&he0 then
          w3=wg
          '
          'REREFERENCE SAFELY
            w1=strinit(pax(pa),wg) : w3=pecx
          if e<=48 then
            for a=e to 48
              w1+="mov "+qecx+cm+pecx+cr 'DEREF [ecx]
              w3=pecx
            next
          end if
        else 'tg<>&he0
          w1=""
          if e=48 then
            w3=wg 'PASS VALUE
          elseif e=47 then
            w1=medi+wg+cr
            w3=pedi 'DEREF FOR CHARACTER
          else
            w1=leaedi(wg) 'PASS ADDRESS
            w3=qedi
          end if
        end if
        '
        pas(pa)=pax(pa)
        pav(pa)=w1+callcnvi(c,w3,e) 'itr w2
        goto nxtel
      end if
      '
    end if
    '
    'fall thru
    '
    'ert=17 : ers="param compatibility problem "+wg
    '
    '===================
    nxtel: 'NEXT ELEMENT
    '===================
    '
    c+=1
    '
  loop
  '
  compatsx:
  '
  if k then
    if apa=0 then
      pc=pc+(e2-e1) 'OPTIONAL PARAM FILL IN
    end if
  end if
  '
  indt=oindt
  function=k
  '
end function

