  '=======================
  'MAIN.INC FOR OXYGEN.DLL
  '=======================

  #autodim disabled
  indexbase 0
  '
  extern lib "kernel32.dll"
  =========================
  ! GetModuleFileName "GetModuleFileNameA"
  ! VirtualAlloc
  ! VirtualProtect
  ! VirtualFree
  end extern
  '
  'TIME
  =====
  uses ..\TimeUtil
  '
  $ o2datetimestamp "2026-04-20T13:39:57"
  '
  'GLOBAL STATE
  '============
  '
  uses glob 'GLOBAL VARIABLES
  '
  string utfs        'storage for UTF-16 strings
  int utfi           'buffer index (starts with 0)
  int utfb=249       'EMBEDDED UTF-8 MARKER
  int utfc=248       'EMBEDDED UTF-16 MARKER
  int omo            'oxygen io string mode


  'READING AND RECORDS
  '===================
  '
  uses lexi 'LEXING / LOWER PARSING
  uses utft 'UTF SCRIPT CONVERSION
  uses reco 'RECORDS / HASH STORAGE
  '
  'MACHINE CODING
  '==============
  '
  uses link 'O2 MACHINE SCRIPT LINKER
  uses assm 'ASSEMBLER (TO O2 MACHINE SCRIPT)
  uses enco 'ASM ENCODING FUNCTIONS
  uses hdrs 'HEADERS FOR EXECUTABLE CODE
  '
  'LANGUAGE
  '========
  '
  uses lang 'INNER CORE DEFINITIONS
  uses pars 'HIGHER LEVEL PARSING
  uses meta 'META-PROGRAMMING
  '
  uses decl 'DECLARATIVES
  uses expl 'LOWER EXPRESSIONS
  uses expr 'HIGHER EXPRESSIONS
  uses tran 'MAIN COMPILATION LAYER
  '
  'COMPILING / ADDING RESOURCES
  '============================
  '
  uses reso 'RESOURCES LINKER
  '

  utfs="" 'clear utf-16 buffer
  utfi=0  'clear utf-16 buffer offset
  '
  /**
    VirtualAlloc VirtualProtect VirtualFree
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx
    https://docs.microsoft.com/en-gb/windows/desktop/Memory/memory-protection-constants
  */
  '
  procedure SetExecSpace()
  ========================
  sys pam,lam
  pam=pvm[ibuf]
  lam=len dbuf
  pbuf=strptr dbuf
  if pam
    VirtualFree pam,0,0x8000 'MEM_RELEASE
  endif
  'MEM_COMMIT, PAGE_EXECUTE_READWRITE
  pam=VirtualAlloc 0,lam,0x1000,0X40
  if pam=0
    ers="prog memory allocation failure"
    ert=47
    exit procedure
  endif
  lbuf[ibuf]=lam
  pvm[ibuf]=pam 'BASE (ALSO ENTRY POINT)
  pvd[ibuf]=pam+posbin[3] 'end of init data , start BSSDATA
  copy pam,pbuf,lam
  '.Text Section protection
  'PAGE_EXECUTE 0x10
  'PAGE_EXECUTE_READ 0x20
  'VirtualProtect pam,posbin[3],0x20,@pr
  end procedure
  '
  '
  'DLL EXPORTED FUNCTIONS
  '======================
  '
  'for compiling and executing
  '
  'extern
  =======

  /**
    set callback to obtain host variable location, by name
  */
  procedure o2_varcall(sys p) export
  ==================================
  pvarcall=p
  end procedure

  /**
    set callback to obtain hosted oxygenBasic path string
  */
  procedure o2_pathcall(sys p) export
  ===================================
  pPathCall=p
  end procedure

  /**
    specify string mode for various o2 API functions
    0 ascii char*
    1 ascii char*
    2 wchar*
    8 ole bstring ascii
    9 ole bstring ascii
    10 ole wbstring wide chars
    16 return mode (altered by UTF-16 detection)
  */
  function o2_mode(int m=16) as int, export
  =========================================
  if m=16
    return omo
  endif
  omo=m
  end function


  /**
    return length of code in current binary code buffer
  */
  function o2_len() as int, export
  ================================
  return lbuf[ibuf]
  end function

  /**
   select current binary code buffer and return pointer
  */
  function o2_buf(int p) as sys, export
  =====================================
  if (p>255)or(p<0)
    ers=" Buffer number out of range (0..255): "+str(p)
  else
    ibuf=p
    return pvm[ibuf]
  endif
  end function


  /**
    return base location of o2 runtime function table
  */
  function o2_lib() as sys, export
  ================================
  return psysfuns
  end function



  /**
    execute binary code in current buffer (or from location specified by pointer
  */
  function o2_exec(sys p=0) as sys, export
  ========================================
  '
  if pef
    return 0 'EXCLUDE (AFTER MAKING A PE FILE)
  endif
  '
  sys mbx,nbx
  '
  if p=0
    p=pvm[ibuf]
    if p=0
      return 0 'NO PROGRAM
    endif
  endif
  '
  mov mbx,rbx
  nbx=pvd[ibuf]
  mov rbx,nbx
  mov rax,0
  call p
  mov rbx,mbx
  return
  '
  end function

  
  /**
    compile o2 machine script to binary and return pointer
  */
  function o2_link(sys isrc) as sys, nosig, export
  ================================================
  gsco=ConvertInput(isrc)
  dbuf=Hexlink(gsco)
  SetExecSpace()
  return pvm[ibuf]
  end function


  /**
  */
  procedure o2_compile() export
  =============================
  int a,le
  string s,w1,w2
  'psysfuns=@sysfuns(0) 'RESTORE ORIGINAL RUNTIME FUN TABLE PTR 'itr multi progs
  gsco=""
  casf=0
  '
  tranpass=1
  '
  'putfile "t.txt",gsrc
  linemark(gsrc)
  '
  declist="" : dlistend=1
  tranpass=2 'WITHOUT UNUSED DECLARE
  proclist="" : plistend=0 'LIST OF PROCEDURES WHICH MAY BE REMOVED IF UNUSED
 'calllist="" : clistend=1 'LIST OF FORWARD REFS TO THE PROCLIST
  gwc=0
  'initial extended record space
  spl=0x200000     'initial string pool 1 meg
  sps=nuls spl     'create clear string pool
  spp=strptr(sps)  'record pointer
  '
  translate(gsrc)
  if compact
    a=len(t)
    markused(t,a)
    compact=0
    if ert
      goto nCompileErr
    endif
    tranpass=3 'EXCLUDING ANY UNUSED PROCEDURES
    gpc=0
    gwc=0
    translate(gsrc)
  endif
  '
  nCompileErr:
  '
  tranpass=0
  '
  '
  if ert=0
    'PARTIAL VIEW
    if (vew=3)and(vwb<>0) 'COMPILE TO INTERMEDIATE CODE OR ASSEMBLY CODE
      le=len(t)
      if vwe=0
        vwe=le+1
      else
        vwe=instr(t,"#endv"+cr)+7
      endif
      vwb=instr(t,"#view"+cr)
      t=mid(t,vwb,vwe-vwb) 'CLIPPED VIEW
    endif
    '
    'CONSTANTS BINDING
    if vwb=0
      w1="|mk 1"+cr+bindlprocs()+"|mk 0"+cr
      w2=left(dats,dati)
      w1+="|td "+hex(dati)+" "+chr(34)+w2+chr(34)+cr
      t=w1+t
    endif
    dati=0
    if abst=0
      t=itran(t) 'PRODUCE ASSEMBLY CODE
    endif
    if vew=3
      gsco=t : exit procedure 'RETURN INTERMEDIATE OR ASM CODE
    endif
    gsas=MakeSections()
    nest()
    intriset(x86_registers)
    gsco=assemble(gsas) 'PRODUCE MACHINE SCRIPT
    unnest()
  else 'errors
    if vew=3
      gsco="Preprocessor error:"+cr+ers+cr+s+cr
    else
      gsco="c3"
    endif
  endif
  end procedure

  /**
  */
  procedure o2_a()
  ================
  int le
  string s
  '
  ert=0 : ers="" : vwb=0 : vwe=0
  '
  o2_compile()
  if vew
    vew=0 : exit procedure 'SCRIPT CODINGS
  endif
  '
  if ert=0
    dbuf=HexLink(gsco) 'PRODUCE EXECUTABLE BINARY
  else
    dbuf=chr(0xc3) 'DEFAULT RET INSTRUCTION
  endif
  '
  '
  'FILING AN EXE OR DLL
  'ADDING RESOURCES
  '
  int a
  '
  if ert
    goto nert
  endif
  if pef
    MakePEfile(pexn) 'PRODUCE PE FILE FROM BINARY
    if ert
      goto nert
    endif
    if resf
      a=AddResources(resf,pexn)
      if a
        ers="Unable to link "+resf+" to "+pexn : ert=44
        'itr cases 1..4
        ert=GetLastError
        goto nert
      endif
    endif
    a=0
    if rss
      a=1
    endif
    if rcf
      a=1
    endif
    if a
      a=BuildResources(rss,rcf,pexn)
      if a
        ers="Unable to compile "+rcf+" into "+pexn : ert=45
        ert=GetLastError
        goto nert
      endif
    endif
  endif 'pef
  '
  'JIT MODE
  if len(dbuf)>0x2000
    'copy over runtime links
    copy strptr(dbuf)+posbin[3],rbx,0x2000 '8192 bytes
  endif
  SetExecSpace()
  '
  nert:
  '
  end procedure 'o2_compile

  /**
  */
  procedure o2_as(sys isrc)
  =========================
  '
  gsrc=ConvertInput(isrc)
  o2_a()
  end procedure

  /**
  */
  function o2_stats() as string export
  ====================================
  function= "" +
  "COMPILATION DATA: " cr cr +
  "output file name: " pexn cr +
  "output file length: " lpef cr cr +
  "source files: " fql cr +
  "source lines: " glc cr +
  "source word parsing: " gwc cr +
  "source length: " gbc cr +
  "assembler script length: " len(gsas) cr +
  "machine script length: " len(gsco) cr +
  "" cr
  
  function+=""+
  "record size: " str(sizeof(drc)) cr +
  "static record count: " me cr +
  "static records length: " str(me*sizeof(drc)) cr +
  "static record string space: " spj cr +
  "max record string space: " spm cr +
  "static var space: " aoffs cr +
  "procedures: " gpc cr +
  "source buffer insert patches: " gi1 cr +
  "source buffer insert renew: " gi2 cr +
  "max link labels: " bkmx cr +
 '"link buffer expansions: " gelb cr +
  "binary image size: " gbo cr +
  ""
  end function

  /**
    compile source code string to binary code, and return pointer
  */
  function o2_basic(sys isrc) as sys, nosig, export
  =================================================
  o2_as(isrc)
  return pvm[ibuf]
  end function

  /**
  */
  function O2_Vp(sys isrc) as sys
  ===============================
  gsrc=ConvertInput(isrc)
  o2_a()
  return ConvertOutput(gsco)
  end function

  /**
    compile source code string and return o2 machine script string
  */
  function o2_view(sys isrc) as sys, nosig, export
  ================================================
  vew=2 : return O2_Vp(isrc)
  end function

  /**
    compile source code string and return assembly code string
  */
  function o2_prep(sys isrc) as sys, nosig, export
  ================================================
  vew=3 : return O2_Vp(isrc)
  end function


  /**
    compile source code string and return intermediate code string
  */
  function o2_abst(sys isrc) as sys, nosig, export
  ================================================
  abst=1 : vew=3 : function=O2_Vp(isrc) : abst=0
  end function


  /**
    return error number, if any
  */
  function o2_errno() as sys, export
  ==================================
  return ert
  end function

  'also needed:
  'errdesc
  'errline
  'errfile


  /**
    return compiling error string, if any
  */
  function o2_error() as sys, export
  ==================================
  return ConvertOutput(ers)
  end function

  /**
    return version string, include time/datestamp
  */
  function o2_version() as sys, export
  ====================================
  return ConvertOutput(o2version+" "+o2datetimestamp)
  end function


  'end extern


  'ENTRY CODE
  ===========
  '
  psysfuns=rbx
  'omo=0 'null terminated ascii
  omo=9  'olestring ascii
  pvarcall=0 'callback for host var pointers. Set by o2_varcall
  RootDir=nuls 256
