Author Topic: Macros as Functions: #return  (Read 596 times)

0 Members and 1 Guest are viewing this topic.

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3751
    • Oxygen Basic
Macros as Functions: #return
« 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:

Code: [Select]
'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

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3751
    • Oxygen Basic
Re: Macros as Functions: without #return
« Reply #1 on: March 03, 2018, 02:54:39 AM »
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:
Code: [Select]
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

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3751
    • Oxygen Basic
Re: Macros as Functions: PB asc()
« Reply #2 on: March 03, 2018, 03:36:28 AM »

Using the same technique, we can emulate PB's asc(), which works as both a statement and a function.

Code: [Select]
  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

Arnold

  • Hero Member
  • *****
  • Posts: 677
Re: Macros as Functions: #return
« Reply #3 on: May 01, 2018, 11:59:37 PM »
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
Code: [Select]
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
« Last Edit: May 02, 2018, 11:23:25 AM by Arnold »

Arnold

  • Hero Member
  • *****
  • Posts: 677
Re: Macros as Functions: #return
« Reply #4 on: May 02, 2018, 11:24:14 AM »
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.

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3751
    • Oxygen Basic
Re: Macros as Functions: #return
« Reply #5 on: May 02, 2018, 07:16:16 PM »
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:

Code: [Select]
macro arr3d int* (r,x,y,z)
  'r return value
  @r=@arr( (x)*2*4 + (y)*4 + (z) )
end macro       

Arnold

  • Hero Member
  • *****
  • Posts: 677
Re: Macros as Functions: #return
« Reply #6 on: May 02, 2018, 11:53:20 PM »
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:
Code: [Select]
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

Charles Pegge

  • Admin Support Member
  • *****
  • Posts: 3751
    • Oxygen Basic
Re: Macros as Functions: #return
« Reply #7 on: May 03, 2018, 01:19:24 AM »
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.