 
'CO2.INC

'Compiler for OxygenBasic
'========================

'Charles Pegge
'11/06/2015
'06/03/2017
'13/01/2018
'26/08/2018
'29/05/2019
'28/06/2019
'28/07/2019
'29/07/2022
'02/10/2022
'31/05/2023
'27/06/2024
'26/10/2024
'15/10/2025
'09/02/2026
'17/04/2026
/*
  '32 BIT COMPILER
  #compact
  def SelectRTL uses RTL32
  def SelectExtern extern lib "oxygen.dll"
  def Filename "co2.exe"
  uses co2
*/

/*
  '64 BIT COMPILER
  #compact
  def SelectRTL uses RTL64
  def SelectExtern extern lib "oxygen64.dll"
  def Filename "co2m64.exe"
  uses co2
*/


  SelectRTL
  %NoConsole
  uses console
  uses SysUtil
  uses oxygen.res

  SelectExtern
  uses oxygenAPI
  end extern

  StrBuffer pr

  sys    a,i
  string s,t,u
  sys    swa,swc,swl,swm,swr,sws  'COMPILER SWITCHES
  string fname,mname,xname    'SOURCE FILE NAME COMPONENTS
  string bfname,bmname,rfname 'PE FILE NAME COMPONENTS
  string er                   'ERROR MESSAGES
  '
  int utfb=249 'embedded encode mark
  int utfc=248 'embedded unicode mark
  '

  s=CommandLineArgs()  

  if not s then goto nofile
  '
  'SWITCHES
  '========
  i=0
  do
    i++ : skiplspace s,i
    if ascb<>45 then exit do
    i++ : skiplspace s,i
    select ascb
    case "i" : swa=ascb '-i intermediate output
    case "a" : swa=ascb '-a asm output
    case "b" : swa=ascb       '-b o2 output
    case "c" : swc=ascb       '-c compile 32bit
    case "3" : swc=ascb : i++ '-c compile 32bit
    case "6" : swc=ascb : i++ '-c compile 64bit
    case "m" : swm=1          '-m do not show messagebox
    case "d" : swl=1          '-d dll binary
    case "r" : swr=1          '-r run binary file
    case "j" : swc=0x30 : i++ : exit do ' -jit mode arguments 
    end select
  end do
  '
  s=mid(s,i)
  '
  nofile: 'check
  '=============
  '
  if not s then
  pr.in "
  compiler options:
  <filename>       compile and execute directly in memory
  -a <filename>    list assembly code
  -b <filename>    list o2 machine script
  -c <filename>    <optional filename>  compile to 32bit binary
  -32 <filename>   <optional filename>  compile to 32bit binary
  -64 <filename>   <optional filename>  compile to 64bit binary
  -i <filename>    list intermediate code
  -m               output to console
  -d               compile to DLL instead of EXE
  -r               run compiled file
  -j               jit mode arguments follow
  add <filename.res> to link resources
  "
  jmp fwd done
  end if
  '
  'GET FILENAMES
  '=============
  '
  string s2,s3
  i=1
  s2=getword(s,i)
  s2=unquote(s2)
  s3=right(s2,6)
  a=len(s2)
  if s3=".o2bas"
    fname=s2
    a-=6
  else
    s3=right(s2,4)
    if s3=".bas"
      fname=s2
      a-=4
    else
      fname=s2+".o2bas"
    endif
  endif
  mname=left(fname,a)
  '
  if swc=0x30 'jit command line
    swc=0
    jmp fwd nargl 'skip do loop
  endif
  '
  do
    s2=getword(s,i)
    s2=unquote(s2)
    if lenw=0
      exit do
    endif
    s3=right(s2,4)
    if s3=".exe"
      bfname=s2
      swl=0
      if swc=0
        swc=0x33 '-32
      endif
    elseif s3=".dll"
      bfname=s2
      swl=1
      if swc=0
        swc=0x33 '-32
      endif
    elseif s3=".res"
      rfname=s2
      sws=1
    else 'assume no extension name
      bfname=s2+".exe"
      swl=0
      if swc=0
        swc=0x33 '-32
      endif
    endif
  loop
  '
  nargl:
  '
  'ATTEMPT TO GET FILE
  '===================
  '
  t=getfile fname
  if not t then
    pr.in "error: file empty or not found: "+fname
    jmp fwd done
  endif
  '
  u=""
  '
  if swc or swl
    string cf
    if bfname="" then
      if swl
        bfname=".dll"
      else
        bfname=".exe"
      endif
      bfname=mname+bfname
    endif
    cf="uses RTL32"
    select swc
    case "6"     : cf="uses RTL64"
    end select
    if swl
      u+="$dll"+cr
    endif
    if sws
      cf+=cr+"uses "+rfname
    endif
    u+="$filename "+qu+bfname+qu+cr+cf+cr
  endif
  '
  if u
    t=u+"uses "+qu+fname+qu+cr
  endif
  '
  '
  'NORMAL COMPILE
  '==============

 'o2_mode 0  'read/return null terminated ascii strings
  o2_mode 9   'ascii string (1: byte characters) (8: ole string)
  '
  select swa
  case "a"  : pr.in o2_prep(t) 'OUTPUT ASSEMBLY CODE
  case "b"  : pr.in o2_view(t) 'OUTPUT O2 MACHINE SCRIPT (AFTER ASSEMBLY CODE)
  case "i"  : pr.in o2_abst(t) 'OUTPUT INTERMEDIATE CODE (BEFORE ASSEMBLY CODE)
  case else :       o2_basic t 'COMPILE TO EXECUTABLE BINARY
  end select
  '
  int exitcode=o2_errno()
  '
  if exitcode then
    pr.in cr+o2_error()
    jmp fwd done
  else
    if swc=0 then
      exitcode=o2_exec 0 'JIT mode
    else 'swc<>0 'COMPILED MODES
      'if sws
      '  exitcode=AddResources(rfname,bfname)
      'endif
      if swr
        if exitcode=0
          exitcode=exec(bfname) 'EXEC FILE 0 do not wait
        endif
      else
        if swm
          pr.in cr+"Okay"
        endif
      endif
    end if
  end if

  done:
  =====

  'DISPLAY RESULTS
  sys ho,lew
  string prs=pr.out
  if len(prs) then
   if swm=0 then
      if 2 and o2_mode()
        MessageBoxW 0,prs,L"o2 unicode",0
      else
        mbox prs
      endif
    else
      'sys p=GetCurrentProcess() '-1 parent process
      AttachConsole(-1) 'attach to console of parent process
      output prs
      sys ho=GetStdHandle( STD_OUTPUT_HANDLE )
      if ho<>consout then consout=ho : output prs 'windows 10
      sleep 10
      FreeConsole
    end if
  end if
  prs+=cr cr fname cr cr o2_stats()
  putfile AppExePath()+"co2.txt",prs
  '
  return exitcode


