Oxygen Basic
Programming => Example Code => General => Topic started by: Charles Pegge on February 03, 2018, 07:27:33 AM
-
One-liner macros are easy to embed in expressions, but multi-line macros require an additional step. Namely to substitute a proxy variable for the macro within the expression, then the macro can be instantiated in advance.
#return specifies the variable to be substituted, carrying the 'output' of the macro. The type of the variable (int here) is placed after the macro name:
'USING MACRO FUNCTIONS
'2D ARRAY WITH BOUNDARY CLIPPING
indexbase 0
int pix[800*600]
'
'SINGLE-LINE MACRO FUNCTION
'macro pix2d(x,y) pix(y*800+x)
'
'MULTI-LINE MACRO RETURNING A UNIQUE VARIABLE
macro pix2d int (x,y, v,vv)
#return *v 'pointer supports reading and writing in pix
if x>=0 and x<800 and y>=0 and y<600
@v=@pix(y*800+x)
else
int vv=0xffffffff 'value when out of bounds
@v=@vv
end if
end macro
'
'TEST
pix2d(1,20)=0xaabbccdd
print hex pix2d(1,20)
print hex pix2d(800,10)
Using Oxygen.dll in OxygenProgress.zip and OxygenBasicProgress.zip (from 1 Feb 2018)
https://github.com/Charles-Pegge/OxygenBasic
-
A change in notation:
If the macro specifies a return-type in its header, then the first parameter specifies the return-variable. So the example, given above, now becomes:
indexbase 0
int pix[800*600]
'
macro pix2d int* (v,x,y, vv)
=============================
'v return pixel pointer supporting read/write
'x horizontal coordinate
'y vertical coodinate
'vv sink pixel
if x>=0 and x<800 and y>=0 and y<600
@v=@pix(y*800+x)
else
int vv=0xffffffff 'value when out of bounds
@v=@vv
end if
end macro
'
'TEST
pix2d(1,20)=0xaabbccdd
print hex pix2d(1,20)
print hex pix2d(800,10)
Using Oxygen.dll in OxygenProgress.zip (from 3 Mar 2018)
https://github.com/Charles-Pegge/OxygenBasic/blob/master/OxygenProgress.zip
-
Using the same technique, we can emulate PB's asc(), which works as both a statement and a function.
macro asc ubyte* (a, s="",i=1)
==============================
'a ascii code return
's string input
'i character index expression
'
@a=_asc_(strptr(s),len(s),i)
end macro
'
function _asc_(sys pt,int le,i) as ubyte*
=========================================
'le string length
'pt string pointer
'si sink location for out of bounds ascii
'oo character offset position
static int si
sys oo=(i)-1
if oo<-1 then oo+=le+1 'offset from right
if oo>=le or oo<0 or pt=0 then
return @si 'sink
else
return pt+oo 'success
end if
end function
'#recordof _asc_
'TEST
=====
bstring s="1234"
asc(s)=65
asc(s,2)=66
asc(s,-2)=67
print s ", " asc(s,-1) 'ABC4, 52
print asc(s,1000) '0
del s
-
Hi Charles,
using your example code, I tried to create a 3-dimensional array in three ways. Only using the function iarr will show the correct results. Am I missing something with the macro iarr? I am also not sure if I forgot something with macro arr3d?
Roland
uses console
#autodim off
indexbase 0
int arr[3*2*4]=
{11, 12, 13, 14,
15, 16, 17, 18,
21, 22, 23, 24,
25, 26, 27, 28,
31, 32, 33, 34,
35, 36, 37, 38}
function iarr(int x,y,z) {return x*2*4 + y*4 + z}
'macro iarr(x,y,z) (x*2*4 + y*4 + z)
macro arr3d int* (r,x,y,z)
'r return value
@r=@arr(x*2*4 + y*4 + z)
end macro
printl "- 3D Array Elements - " + cr +cr
int i, j, k
int idx
for i=0 to <3
for j=0 to <2
for k=0 to <4
idx = iarr(i,j,k)
print arr[idx] : print tab
' print arr3d(i,j,k) : print tab
next
printl
next
printl
next
printl "-----------------------------" : printl : printl
for i=0 to <3
for j=0 to <2
for k=0 to <4
idx = i*2*4 +j*4 +k
print idx tab
next
printl
next
printl
next
printl "Enter ..." : waitkey
-
After further considerations I think I can also use a function for arr3d:
...
function arr3d(int x,y,z) as int
int idx=x*2*4 + y*4 + z
sys a*
@a = @arr
return a[idx]
end function
...
print arr3d(i,j,k) : print tab
This will give the expected results and I can also use expressions for the parameters.
-
Hi Roland,
Thanks for testing macro functions.
If you want to pass expressions to a macro, then they will need to be contained within parentheses, inside the macro:
macro arr3d int* (r,x,y,z)
'r return value
@r=@arr( (x)*2*4 + (y)*4 + (z) )
end macro
-
Thank you Charles. The brackets made the difference and the macro works fine.
Perhaps there is also something possible with the macro iarr? To find the index for 2d array is no problem, but for more dimensions only the values of the first loop of i are correct. Unfortunately I am not familiar with your debugging tools and using print statements in macros seems not to be really helpful.
This is the code to get the index of an emulated 2d array:
uses console
#autodim off
indexbase 0
int ar[6*4] =
{11, 12, 13, 14,
15, 16, 17, 18,
19, 20, 21, 22,
23, 24, 25, 26,
27, 28, 29, 30,
31, 32, 33, 34}
macro iar(x,y) (x*4 + y)
int i, j
int idx
for i=0 to <6
for j=0 to <4
idx = iar(i,j)
print ar[idx] : print tab
next
printl
next
printl "Enter ..." : waitkey
-
Line numbers are currently removed from macros, making late debugging more tricky. But you can plant a few labels or virtual line-numbers to help with code tracing. This is useful in situations where macros invoke other macros, and you need to know which one is misbehaving.
Diagnostics inside a macro, such as #show, #recordof, or print, are useful, but nothing will happen, of course, until the macro is invoked.