Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Why can't I invoke this external routine?

Status
Not open for further replies.

rexxhead

Programmer
Jul 31, 2002
611
US
I have the following subroutine (ooREXX on Windows):
[pre]
/* REXX external subroutine */
/* ----------------------------------------------------------------- */
SQRT: /*@ */
arg nbr .
parse var nbr whole "." frac
if \Datatype(whole,"W") then whole = 0
if \Datatype(frac ,"W") then frac = 0; else frac = "."frac
if Length(whole)//2 = 0 then parse var whole base 3 tail
else parse var whole base 2 tail
root = (base/2) * (10**(Length(tail)%2)) + frac
numeric digits 12
lastdiff = 0
do forever
diff = nbr - root**2
if diff = 0 then leave
if diff = lastdiff then leave
lastdiff = diff
root = root + ((diff/2) /root)
end
numeric digits 11
root = root + 0
root = Strip( root , "T" , '0' )
root = Strip( root , "T" , '.' )
return root /*@ SQRT */
[/pre]

It lives in the same directory as its caller and is called as
[pre]
area = SQRT( s *(s-a )*( s-b )*( s-c ) )​
[/pre]
That statement blows up with "routine not found". When I make SQRT an internal routine, everything works as designed. What am I doing wrong?

Frank Clarke
--America's source for adverse opinions since 1943.
 
Hi, it works for me:

I stored your subroutine SQRT in a file with the same name, i.e.:
sqrt.rex
Code:
SQRT:
  say "* Subroutine SQRT by rexxhead"
  arg nbr .
  parse var nbr whole "." frac
  if \Datatype(whole,"W") then whole = 0
  if \Datatype(frac ,"W") then frac  = 0; else frac = "."frac
  if Length(whole)//2 = 0 then parse var whole base 3 tail
                          else parse var whole base 2 tail
  root = (base/2) * (10**(Length(tail)%2)) + frac
  numeric digits 12
  lastdiff = 0
  do forever
    diff = nbr - root**2
    if diff = 0 then leave
    if diff = lastdiff then leave
    lastdiff = diff
    root  =  root + ((diff/2) /root)
  end
  numeric digits 11
  root = root + 0
  root = Strip( root , "T" , '0' )
  root = Strip( root , "T" , '.' )
return root

then I created in the same directory the second source file:
caller_01.rex
Code:
-- test the function
x = 1000
y = sqrt(x)
say "x =" x
say "sqrt("||x||") =" y 
exit

calling it delivers result
Code:
c:\00_mikrom\Work\REXX>rexx caller_01.rex
* Subroutine SQRT by rexxhead
x = 1000
sqrt(1000) = 31.622776602

 
Does it work if you eliminate the 'rexx' and the '.rex'?
[pre]

c:\00_mikrom\Work\REXX>caller_01[/pre]?

That's how I'm calling it:
[pre]

F:\REXX\ooREXXcode>hero 13 14 15
A triangle with sides 13 14 15 has an area of 84[/pre]

Frank Clarke
--America's source for adverse opinions since 1943.
 
rexxhead said:
Does it work if you eliminate the 'rexx' and the '.rex'?

yes it works:
Code:
c:\00_mikrom\Work\REXX>caller_01.rex
x = 1000
* Subroutine SQRT by rexxhead
sqrt(1000) = 31.622776602


c:\00_mikrom\Work\REXX>caller_01
x = 1000
* Subroutine SQRT by rexxhead
sqrt(1000) = 31.622776602
 
Maybe at 78 I'm just starting to show signs of dementia.

I copied yours just to prove it works in my environment. It worked.

I copied my original, excised the internal SQRT code, and moved the complex multiplication outside the call and just did "area = SQRT(x)". It worked.

I modified the original to just excise the internal SQRT code. It worked.

I have no idea why it works now and didn't work then.

Thank you for your patience.



Frank Clarke
--America's source for adverse opinions since 1943.
 
Probably you got the error, because the name of your source file where the code of the function SQRT is stored was not exactly sqrt.rex or sqrt

First I named my source file with SQRT functions.rex, thinking that I could have in one source file more functions, but then I got the error like you.

 
I'm not sure if it's possible in standard REXX to have multiple external routines stored in one file.
But in ooREXX we can do that with the built-in ::routine and ::requires commands.
Here is the example:

I have this source file which contains two functions tagged with ::routine and public

functions.rex
Code:
::routine sqrt public
  say "* Function: SQRT by rexxhead"
  arg nbr .
  parse var nbr whole "." frac
  if \Datatype(whole,"W") then whole = 0
  if \Datatype(frac ,"W") then frac  = 0; else frac = "."frac
  if Length(whole)//2 = 0 then parse var whole base 3 tail
                          else parse var whole base 2 tail
  root = (base/2) * (10**(Length(tail)%2)) + frac
  numeric digits 12
  lastdiff = 0
  do forever
    diff = nbr - root**2
    if diff = 0 then leave
    if diff = lastdiff then leave
    lastdiff = diff
    root  =  root + ((diff/2) /root)
  end
  numeric digits 11
  root = root + 0
  root = Strip( root , "T" , '0' )
  root = Strip( root , "T" , '.' )
return root

::routine integer_of_sqrt public
  say "* Function: Integer Part of Square Root"
  n = arg(1)
  r = 0
  do while (r*r <= n)
    r = r + 1
  end
  r = r - 1
return r

Then I have this source file with the main program which ::requires "functions.rex" and call the external routines

caller_02.rex
Code:
-- test functions
x = 1000
say "x =" x
say

y = sqrt(x)
say "sqrt("||x||") =" y 
say

y = integer_of_sqrt(x)
say "integer_of_sqrt("||x||") =" y
say 
exit

::requires "functions.rex"

Note, that ::requires statement should be placed at the end of the source file.

Now, running caller_02 delivers the following results:
Code:
c:\00_mikrom\Work\REXX>caller_02
x = 1000

* Function: SQRT by rexxhead
sqrt(1000) = 31.622776602

* Function: Integer Part of Square Root
integer_of_sqrt(1000) = 31
 
No, standard REXX doesn't include the notion of a library of external routines, dammit, nor does it allow (as PL/I and COBOL) to INCLUDE blocks of external text. The latter, in fact, would practically eliminate the need for the former.

Oh, how I would love to be able to [pre]

/* REXX Routine */
%INCLUDE stdfront
call a_init
call b_prolog
call m_main_processing
call z_epilog
%INCLUDE stdback
[/pre]

Instead, I copy in my canonical boilerplate code and then insert code to do whatever the instant function calls for.

Frank Clarke
--America's source for adverse opinions since 1943.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top