• Welcome to Theos PowerBasic Museum 2017.

Making an OxygenBasic compiler with PB

Started by Charles Pegge, February 27, 2013, 01:21:51 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Charles Pegge

Oxygenbasic comes in the form of a single-32 bit DLL. It can be used for both immediate compile/execute and for producing conventional PE binary files.

This is the current API for PowerBasic use.


'OxygenBasic API for PowerBasic
'10:07 28/02/2013
'Charles Pegge

  MACRO oxy="..\..\oxygen.dll"
  DECLARE FUNCTION o2_asmo      LIB oxy ALIAS "o2_asmo"      (BYVAL STRING) AS STRING      ' compile
  DECLARE FUNCTION o2_basic     LIB oxy ALIAS "o2_basic"     (BYVAL STRING) AS STRING      ' compile
  DECLARE FUNCTION o2_exec      LIB oxy  ALIAS "o2_exec"     (OPTIONAL BYVAL LONG) AS LONG ' run compile program
  DECLARE FUNCTION o2_link      LIB oxy ALIAS "o2_link"      (BYVAL STRING) AS STRING      ' o2 link **
  DECLARE FUNCTION o2_view      LIB oxy ALIAS "o2_view"      (BYVAL STRING) AS STRING      ' o2 coding
  DECLARE FUNCTION o2_prep      LIB oxy ALIAS "o2_prep"      (BYVAL STRING) AS STRING      ' assembly code (x86)
  DECLARE FUNCTION o2_abst      LIB oxy ALIAS "o2_abst"      (BYVAL STRING) AS STRING      ' abstract assembly code
  DECLARE FUNCTION o2_error     LIB oxy ALIAS "o2_error"     ()        AS STRING           ' error message if any
  DECLARE FUNCTION o2_errno     LIB oxy ALIAS "o2_errno"     ()        AS LONG             ' error number or zero
  DECLARE FUNCTION o2_len       LIB oxy ALIAS "o2_len"       ()        AS LONG             ' length of returned string
  DECLARE FUNCTION o2_buf       LIB oxy ALIAS "o2_buf"       (BYVAL LONG)AS LONG           ' buffer selector 0..511 (returns pointer)
  DECLARE SUB      o2_mode      LIB oxy ALIAS "o2_mode"      (BYVAL LONG)                  ' set string i/o mode: 1 asciiz 9  bstring (pb)
  DECLARE SUB      o2_put       LIB oxy ALIAS "o2_put"       (BYVAL STRING)                ' load code into an exec buffer
  DECLARE FUNCTION o2_get       LIB oxy ALIAS "o2_get"       ()AS LONG                     ' get pointer to code in exec buffer


And here is a minimal example of using OxygenBasic:


#COMPILE EXE
#DIM ALL
#INCLUDE "OxygenPb.inc"

FUNCTION PBMAIN () AS LONG
DIM s AS STRING
'
s="print 100+20+3"
'
o2_basic s
IF o2_errno THEN
  MSGBOX o2_error(),%MB_OK,"Oxygen"
ELSE
  o2_exec
END IF
END FUNCTION


Charles

Theo Gottwald


Jon Eskdale

Thanks Charles - Just what I've been looking for, for a while.  Much appreciated


Charles Pegge

#3
To produce independent EXE/DLL files, one of the runtime libraries is included at the top of the source:


'COMPILING 32BIT OR 64BIT PE FILES

#COMPILE EXE
#DIM ALL
#INCLUDE "OxygenPb.inc"

FUNCTION PBMAIN () AS LONG
DIM exe32 AS STRING
DIM exe64 AS STRING
DIM t AS STRING
'
exe32="%filename `t32.exe`"+$CRLF+"include `..\..\inc\RTL32.inc`"+$CRLF
exe64="%filename `t64.exe`"+$CRLF+"include `..\..\inc\RTL64.inc`"+$CRLF
t="print 100+20+3"
'
o2_basic exe64+t
IF o2_errno THEN
  MSGBOX o2_error(),%MB_OK,"Oxygen"
END IF
END FUNCTION


Charles

Charles Pegge


The run time libraries contain all the core functions that OxygenBasic knows about. It only includes the bare essentials, so it is quite a small set. But the compiler can be deployed to add its own library extensions.

Also, by adding alternative syntax translation  and error-trapping, it is possible to build a new language shell around this kernel.



John Spikowski


Jon Eskdale

Just wondering - being lazy really but then there is no point re inventing the wheel.  Is there any code to pass PowerBasic variables to the OxygenBasic in existence, this would be extremely useful.
Jon

Charles Pegge

#7
Yes,sharing variables directly between a PB host program and OxygenBasic at run time, in memory, not using a DLL.

This is a little complex but very efficient once set up.

On o2_exec, Oxygen returns a table of functions back to PB.
PB can then pass a VARPTR to Oxygen..
Then both sides have mutual access to the PB host variables.
The Oxygen program is finally terminated to release its memory allocations.

PB side

#COMPILE EXE
#DIM ALL
#INCLUDE "OxygenPb.inc"

DECLARE SUB ShareWithOxygen(BYVAL pv AS LONG PTR, BYVAL n AS LONG)
DECLARE SUB ShowHostVars()
DECLARE SUB EndOxygen()

FUNCTION PBMAIN () AS LONG
DIM SharedVars(1024) AS STATIC LONG
DIM s AS STRING
DIM a  AS LONG PTR
DIM pv AS LONG PTR
DIM i  AS LONG
'
'SOME DATA
'
FOR i=0 TO 9
  SharedVars(i)=i*2
NEXT
'
'COMPILE
'
s="Include `ShareVarsWithHost.o2bas`"
o2_basic s
IF o2_errno THEN
  MSGBOX o2_error(),%MB_OK,"Oxygen"
ELSE
  a=o2_exec
  'msgbox(hex$(a)+"  "+hex$(@a[0])+"  "+hex$(@a[1]))
  CALL DWORD @a[0] USING ShareWithOxygen (VARPTR(SharedVars(0)),10)
  CALL DWORD @a[1] USING ShowHostVars
  '...
  CALL DWORD @a[2] USING EndOxygen
END IF
END FUNCTION


Oxygen side: ShareVarsWithHost.o2bas




sys *HostVars 'accepts vartptr to host variable block
sys nHostVars 'number of variables in block

sub ShareWithOxygen(sys a,n) external
=====================================
@hostvars=a
nhostvars=n
end sub

sub ShowHostVars() external
===========================
sys i
string pr="Host variables:"+chr(13,10)
for i=1 to nHostVars
  pr+=HostVars[i]+chr(13,10)
next
print pr
end sub

sub EndOxygen() external
========================
terminate
end sub

sys ProcTable[3]={&ShareWithOxygen,&ShowHostVars,&EndOxygen}

= &ProcTable
end


You can of course, also  use the subs and functions for passing data in the conventional way

Charles

Jon Eskdale

Thanks Charles - you have saved me hours of work and probably a lot of others if they have the sense to use your very useful OxygenBasic
Thanks again - Much appreciated
Jon

Charles Pegge

You are welcome John. I am collecting these examples together in the Oxygen in-progress version. The folder is currently ProjectsB/PowerBasic