Accessing a local macro value in an outside macro

classic Classic list List threaded Threaded
25 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Accessing a local macro value in an outside macro

Andy W
I have a macro (!DashStr) that takes an input string and returns a string the same length except all dashes. (The motivation for this is to produce simple text tables in Markdown with pandoc.) I want to call this macro multiple times within another macro. I don't know how to access the local value (here named !D) returned from the !DashStr macro in the outer !MarkTable macro that calls it. Below is a simplified example.

*************************************************.
DEFINE !DashStr ( !POSITIONAL = !CMDEND )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
!DashStr !1.
PRINT /!QUOTE(!D) /!1.
!ENDDEFINE.

DATA LIST FREE /X.
1
END DATA.
PRESERVE.
SET MPRINT ON.
!MarkTable X.
RESTORE.
*************************************************.

You can see that the resulting command is [PRINT /'!D' /X] and I want it to be [PRINT /'-' /X]. So how do I access !D in the !MarkTable macro? Or in other words, how do I return a macro variable to be used outside of that local macro environment.
Andy W
apwheele@gmail.com
http://andrewpwheeler.wordpress.com/
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

David Marso
Administrator
Andy,
Macro doohickies/'variables' are completely LOCAL.
However the following approach can yield favorable outcomes in some situations. ;-)
Note changes in BOLD.

DEFINE !DashStr ( !POSITIONAL = !TOKENS(1) )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!CONCAT(!QUOTE(!D))
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND ) .
PRINT /!DashStr !1 /!1. 
!ENDDEFINE.

DATA LIST FREE /X.
BEGIN DATA
1
END DATA.
PRESERVE.
SET MPRINT ON.
!MarkTable X.
EXECUTE.
RESTORE.
<Output>
-
    1.00
Andy W wrote
I have a macro (!DashStr) that takes an input string and returns a string the same length except all dashes. (The motivation for this is to produce simple text tables in Markdown with pandoc.) I want to call this macro multiple times within another macro. I don't know how to access the local value (here named !D) returned from the !DashStr macro in the outer !MarkTable macro that calls it. Below is a simplified example.

*************************************************.
DEFINE !DashStr ( !POSITIONAL = !CMDEND )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
!DashStr !1.
PRINT /!QUOTE(!D) /!1.
!ENDDEFINE.

DATA LIST FREE /X.
1
END DATA.
PRESERVE.
SET MPRINT ON.
!MarkTable X.
RESTORE.
*************************************************.

You can see that the resulting command is [PRINT /'!D' /X] and I want it to be [PRINT /'-' /X]. So how do I access !D in the !MarkTable macro? Or in other words, how do I return a macro variable to be used outside of that local macro environment.
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me.
---
"Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis."
Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?"
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Andy W
Thank you, I will be able to work with that to get where I want. What I had originally wanted was to use it on the right hand side of a !LET statement. It doesn't seem to behave the same way in both instances.

****************************************************.
DEFINE !DashStr ( !POSITIONAL = !ENCLOSE("(",")") )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!QUOTE(!D)
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
ECHO !DashStr(!1).
!LET !A = !DashStr(!1)
ECHO !A
!ENDDEFINE.

!MarkTable 333.
****************************************************.

I thought instead of using [!LET !A = !DashStr(!1)] if you used [!LET !A = !EVAL(!DashStr) (!1)] that would do the trick, but this causes SPSS to forever expect a command that isn't supplied (it says "Running EVAL parameter 1 COMMAN..." in the footer of all the windows).

Also was there a special reason for the !CONCAT in your original proposal? (It doesn't seem to be needed as far as I can tell.)
Andy W
apwheele@gmail.com
http://andrewpwheeler.wordpress.com/
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Bruce Weaver
Administrator
Andy, I got an error message when I ran your code.  To make it run without any errors, I had to remove the period from the first ECHO line in your !MarkTable macro.  

HTH.


Andy W wrote
Thank you, I will be able to work with that to get where I want. What I had originally wanted was to use it on the right hand side of a !LET statement. It doesn't seem to behave the same way in both instances.

****************************************************.
DEFINE !DashStr ( !POSITIONAL = !ENCLOSE("(",")") )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!QUOTE(!D)
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
ECHO !DashStr(!1).
!LET !A = !DashStr(!1)
ECHO !A
!ENDDEFINE.

!MarkTable 333.
****************************************************.

I thought instead of using [!LET !A = !DashStr(!1)] if you used [!LET !A = !EVAL(!DashStr) (!1)] that would do the trick, but this causes SPSS to forever expect a command that isn't supplied (it says "Running EVAL parameter 1 COMMAN..." in the footer of all the windows).

Also was there a special reason for the !CONCAT in your original proposal? (It doesn't seem to be needed as far as I can tell.)
--
Bruce Weaver
bweaver@lakeheadu.ca
http://sites.google.com/a/lakeheadu.ca/bweaver/

"When all else fails, RTFM."

PLEASE NOTE THE FOLLOWING: 
1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above.
2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/).
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Andy W

Sorry if I wasn't clear - the error message is to be expected (although I'm not sure if I can replicate the behavior you describe). Here is perhaps a more clear example. Basically I was just showing that !DashStr(!1) is fine when passed to the first echo command, but for some reason is not valid when passed on the right hand side of !LET.


****************************************************. 
DEFINE !DashStr ( !POSITIONAL = !ENCLOSE("(",")") ) 
!LET !D = !NULL 
!DO !j = 1 !TO !LENGTH(!1) 
  !LET !D = !CONCAT(!D,"-") 
!DOEND 
!QUOTE(!D) 
!ENDDEFINE. 

DEFINE !MarkTable ( !POSITIONAL = !CMDEND ) 
ECHO !DashStr(!1).
ECHO "Both Above and Below me should be dashes".
!LET !A = !DashStr(!1) 
ECHO !A.
!ENDDEFINE. 

ECHO !MarkTable 333.
****************************************************. 

And here is what my output (V15) says:


ECHO !MarkTable 333.

>Warning # 48 in column 256.  Text: (End of Command)
>The ECHO command requires a single parameter - a quoted string.

---
Both Above and Below me should be dashes

>Error # 1.  Command name: (
>The first word in the line is not recognized as an SPSS command.
>This command not executed.

If you SET MPRINT ON you can see that the !1 parameter from !MarkTable is submitted within the parenthesis, but not expanded. I've tried various code with and without a command terminator after the !LET. This does make it expand to the next line, but still not work as expected.


SET MPRINT ON.
ECHO !MarkTable 333.
 489 M>  ECHO
 490 M>  .

>Warning # 48 in column 256.  Text: (End of Command)
>The ECHO command requires a single parameter - a quoted string.

 491 M>  ECHO '---'
 492 M>  .
---
 493 M>  ECHO 'Both Above and Below me should be dashes'.
Both Above and Below me should be dashes
 494 M>  ( 333 ) ECHO ''

>Error # 1.  Command name: (
>The first word in the line is not recognized as an SPSS command.
>This command not executed.

 495 M>  .

Maybe a more general question, but I can't find a single example (besides the trivial one in the Help) of using !EVAL, so I'm not exactly sure how you are supposed to use it anyway.

Andy W
apwheele@gmail.com
http://andrewpwheeler.wordpress.com/
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Bruce Weaver
Administrator
Ah, okay.  My mistake.  Sorry about that.  I'll defer to David on this one!  ;-)


Andy W wrote
<p>Sorry if I wasn't clear - the error message is to be expected (although I'm not sure if I can replicate the behavior you describe). Here is perhaps a more clear example. Basically I was just showing that <code>!DashStr(!1)</code> is fine when passed to the first echo command, but for some reason is not valid when passed on the right hand side of <code>!LET</code>.</p>
<p><pre><code>
****************************************************.
DEFINE !DashStr ( !POSITIONAL = !ENCLOSE("(",")") )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!QUOTE(!D)
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
ECHO !DashStr(!1).
ECHO "Both Above and Below me should be dashes".
!LET !A = !DashStr(!1)
ECHO !A.
!ENDDEFINE.

ECHO !MarkTable 333.
****************************************************.
</code></pre></p>

<p>And here is what my output (V15) says:</p>

<p><pre><code>
ECHO !MarkTable 333.

>Warning # 48 in column 256.  Text: (End of Command)
>The ECHO command requires a single parameter - a quoted string.

---
Both Above and Below me should be dashes

>Error # 1.  Command name: (
>The first word in the line is not recognized as an SPSS command.
>This command not executed.
</code></pre></p>

<p>If you <code>SET MPRINT ON</code> you can see that the <code>!1</code> parameter from <code>!MarkTable</code> is submitted within the parenthesis, but not expanded. I've tried various code with and without a command terminator after the <code>!LET</code>. This does make it expand to the next line, but still not work as expected.</p>

<p><pre><code>
SET MPRINT ON.
ECHO !MarkTable 333.
 489 M>  ECHO
 490 M>  .

>Warning # 48 in column 256.  Text: (End of Command)
>The ECHO command requires a single parameter - a quoted string.

 491 M>  ECHO '---'
 492 M>  .
---
 493 M>  ECHO 'Both Above and Below me should be dashes'.
Both Above and Below me should be dashes
 494 M>  ( 333 ) ECHO ''

>Error # 1.  Command name: (
>The first word in the line is not recognized as an SPSS command.
>This command not executed.

 495 M>  .
</code></pre></p>

<p>Maybe a more general question, but I can't find a single example (besides the trivial one in the Help) of using <code>!EVAL</code>, so I'm not exactly sure how you are supposed to use it anyway.</p>
--
Bruce Weaver
bweaver@lakeheadu.ca
http://sites.google.com/a/lakeheadu.ca/bweaver/

"When all else fails, RTFM."

PLEASE NOTE THE FOLLOWING: 
1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above.
2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/).
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

David Marso
Administrator
In reply to this post by Andy W
Can't spend time now trying to dig that one out...
On Eval:
Basically it forces macros to be expanded.
--
Consider:
DEFINE !Const ()
 X
!ENDDEFINE .

DEFINE Evaltest () .
ECHO "1".
ECHO !QUOTE(!Const).
ECHO "2".
ECHO !QUOTE(!EVAL(!Const)).
ECHO "3" .
!ENDDEFINE.
SET MPRINT OFF.
EvalTest .

--Output--
1
!Const
2
X
3

Andy W wrote
<p>Sorry if I wasn't clear - the error message is to be expected (although I'm not sure if I can replicate the behavior you describe). Here is perhaps a more clear example. Basically I was just showing that <code>!DashStr(!1)</code> is fine when passed to the first echo command, but for some reason is not valid when passed on the right hand side of <code>!LET</code>.</p>
<p><pre><code>
****************************************************.
DEFINE !DashStr ( !POSITIONAL = !ENCLOSE("(",")") )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!QUOTE(!D)
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
ECHO !DashStr(!1).
ECHO "Both Above and Below me should be dashes".
!LET !A = !DashStr(!1)
ECHO !A.
!ENDDEFINE.

ECHO !MarkTable 333.
****************************************************.
</code></pre></p>

<p>And here is what my output (V15) says:</p>

<p><pre><code>
ECHO !MarkTable 333.

>Warning # 48 in column 256.  Text: (End of Command)
>The ECHO command requires a single parameter - a quoted string.

---
Both Above and Below me should be dashes

>Error # 1.  Command name: (
>The first word in the line is not recognized as an SPSS command.
>This command not executed.
</code></pre></p>

<p>If you <code>SET MPRINT ON</code> you can see that the <code>!1</code> parameter from <code>!MarkTable</code> is submitted within the parenthesis, but not expanded. I've tried various code with and without a command terminator after the <code>!LET</code>. This does make it expand to the next line, but still not work as expected.</p>

<p><pre><code>
SET MPRINT ON.
ECHO !MarkTable 333.
 489 M>  ECHO
 490 M>  .

>Warning # 48 in column 256.  Text: (End of Command)
>The ECHO command requires a single parameter - a quoted string.

 491 M>  ECHO '---'
 492 M>  .
---
 493 M>  ECHO 'Both Above and Below me should be dashes'.
Both Above and Below me should be dashes
 494 M>  ( 333 ) ECHO ''

>Error # 1.  Command name: (
>The first word in the line is not recognized as an SPSS command.
>This command not executed.

 495 M>  .
</code></pre></p>

<p>Maybe a more general question, but I can't find a single example (besides the trivial one in the Help) of using <code>!EVAL</code>, so I'm not exactly sure how you are supposed to use it anyway.</p>
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me.
---
"Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis."
Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?"
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Albert-Jan Roskam
In reply to this post by Andy W
So it may be a good idea to always use !eval (along with all the !quote, !concat, !blanks and what not calls), just in case the caller passes a macro as one of the arguments (?). Without !eval, the first macro call would fail (or at least not give the desired outcome).

define !x () "x" !enddefine.
define !y (!pos !cmdend).
echo !quote(!eval(!1)).
!enddefine.

!y !x.
!y 'x'.



Regards,

Albert-Jan



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

All right, but apart from the sanitation, the medicine, education, wine, public order, irrigation, roads, a

fresh water system, and public health, what have the Romans ever done for us?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--------------------------------------------
On Thu, 1/16/14, David Marso <[hidden email]> wrote:

 Subject: Re: [SPSSX-L] Accessing a local macro value in an outside macro
 To: [hidden email]
 Date: Thursday, January 16, 2014, 12:41 AM

 Can't spend time now trying to dig
 that one out...
 On Eval:
 Basically it forces macros to be expanded.
 --
 Consider:
 DEFINE !Const ()
  X
 !ENDDEFINE .

 DEFINE Evaltest () .
 ECHO "1".
 ECHO !QUOTE(!Const).
 ECHO "2".
 ECHO !QUOTE(!EVAL(!Const)).
 ECHO "3" .
 !ENDDEFINE.
 SET MPRINT OFF.
 EvalTest .

 --Output--
 1
 !Const
 2
 X
 3


 Andy W wrote
 > <p>
 > Sorry if I wasn't clear - the error message is to be
 expected (although
 > I'm not sure if I can replicate the behavior you
 describe). Here is
 > perhaps a more clear example. Basically I was just
 showing that
 > <code>
 > !DashStr(!1)
 > </code>
 >  is fine when passed to the first echo command,
 but for some reason is not
 > valid when passed on the right hand side of
 > <code>
 > !LET
 > </code>
 > .
 > </p>
 > <p>
 > <pre>
 > <code>
 > ****************************************************.
 > DEFINE !DashStr ( !POSITIONAL = !ENCLOSE("(",")") )
 > !LET !D = !NULL
 > !DO !j = 1 !TO !LENGTH(!1)
 >   !LET !D = !CONCAT(!D,"-")
 > !DOEND
 > !QUOTE(!D)
 > !ENDDEFINE.
 >
 > DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
 > ECHO !DashStr(!1).
 > ECHO "Both Above and Below me should be dashes".
 > !LET !A = !DashStr(!1)
 > ECHO !A.
 > !ENDDEFINE.
 >
 > ECHO !MarkTable 333.
 > ****************************************************.
 > </code>
 > </pre>
 > </p>
 >
 > <p>
 > And here is what my output (V15) says:
 > </p>
 >
 > <p>
 > <pre>
 > <code>
 > ECHO !MarkTable 333.
 >
 >>Warning # 48 in column 256.  Text: (End of
 Command)
 >>The ECHO command requires a single parameter - a
 quoted string.
 >
 > ---
 > Both Above and Below me should be dashes
 >
 >>Error # 1.  Command name: (
 >>The first word in the line is not recognized as an
 SPSS command.
 >>This command not executed.
 > </code>
 > </pre>
 > </p>
 >
 > <p>
 > If you
 > <code>
 > SET MPRINT ON
 > </code>
 >  you can see that the
 > <code>
 > !1
 > </code>
 >  parameter from
 > <code>
 > !MarkTable
 > </code>
 >  is submitted within the parenthesis, but not
 expanded. I've tried various
 > code with and without a command terminator after the
 > <code>
 > !LET
 > </code>
 > . This does make it expand to the next line, but still
 not work as
 > expected.
 > </p>
 >
 > <p>
 > <pre>
 > <code>
 > SET MPRINT ON.
 > ECHO !MarkTable 333.
 >  489 M>  ECHO
 >  490 M>  .
 >
 >>Warning # 48 in column 256.  Text: (End of
 Command)
 >>The ECHO command requires a single parameter - a
 quoted string.
 >
 >  491 M>  ECHO '---'
 >  492 M>  .
 > ---
 >  493 M>  ECHO 'Both Above and Below me
 should be dashes'.
 > Both Above and Below me should be dashes
 >  494 M>  ( 333 ) ECHO ''
 >
 >>Error # 1.  Command name: (
 >>The first word in the line is not recognized as an
 SPSS command.
 >>This command not executed.
 >
 >  495 M>  .
 > </code>
 > </pre>
 > </p>
 >
 > <p>
 > Maybe a more general question, but I can't find a
 single example (besides
 > the trivial one in the Help) of using
 > <code>
 > !EVAL
 > </code>
 > , so I'm not exactly sure how you are supposed to use
 it anyway.
 > </p>





 -----
 Please reply to the list and not to my personal email.
 Those desiring my consulting or training services please
 feel free to email me.
 ---
 "Nolite dare sanctum canibus neque mittatis margaritas
 vestras ante porcos ne forte conculcent eas pedibus suis."
 Cum es damnatorum possederunt porcos iens ut salire off
 sanguinum cliff in abyssum?"
 --
 View this message in context: http://spssx-discussion.1045642.n5.nabble.com/Accessing-a-local-macro-value-in-an-outside-macro-tp5723922p5723931.html
 Sent from the SPSSX Discussion mailing list archive at
 Nabble.com.

 =====================
 To manage your subscription to SPSSX-L, send a message to
 [hidden email]
 (not to SPSSX-L), with no body text except the
 command. To leave the list, send the command
 SIGNOFF SPSSX-L
 For a list of commands to manage subscriptions, send the
 command
 INFO REFCARD

=====================
To manage your subscription to SPSSX-L, send a message to
[hidden email] (not to SPSSX-L), with no body text except the
command. To leave the list, send the command
SIGNOFF SPSSX-L
For a list of commands to manage subscriptions, send the command
INFO REFCARD
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Andy W
Can someone give an example of using !EVAL when the expanded macro actually takes an argument? All examples I have been able to dig up are the macros which take no arguments (which I understand are useful for those hacky write an outfile meta programming thing - but doesn't translate to this situation).

*********************************************.
DEFINE !DashStr ( !POSITIONAL = !ENCLOSE("(",")") )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!QUOTE(!D)
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
!LET !A = !EVAL(!DashStr(!1)) .
ECHO !QUOTE(!A).
!ENDDEFINE.
*This macro fails to compile - error message.
*>In a macro expression, a left parenthesis immediately follows an operand.
*>This command not executed.
*********************************************.

Here are a few more versions which compile as valid macro's, but when running produce a message "Running EVAL parameter 1 COMMAN..." in the footer and just hang. After these I have to kill the SPSS process to even exit - so beware! So !EVAL doesn't appear be amenable to expanding a macro that takes arguments.

*********************************************.
DEFINE !DashStr ( !POSITIONAL = !TOKENS(1) )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!QUOTE(!D)
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
!LET !A = !EVAL(!DashStr) !1.
ECHO !A.
!ENDDEFINE.
*This compiles, but when it runs it hangs forever expecting a command.
*MarkTable 333.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
!LET !A = !EVAL(!DashStr) !EVAL(!1) .
ECHO !A.
!ENDDEFINE.
*Ditto with prior.
*MarkTable 333.
*********************************************.


Andy W
apwheele@gmail.com
http://andrewpwheeler.wordpress.com/
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Albert-Jan Roskam
* fails.
define !x (!pos !enclose("(", ")")).
!quote(!concat("tadaah: ", !1))
!enddefine.
define !y (!pos !enclose("(", ")")).
echo !quote(!eval(!1)).
!enddefine.
set mprint = on.
!y(!x(I hate macros)).

* works.
set mprint = off.
begin program.
import spss
def x(v):
    return "tadaah: " + v
def y(v):
    spss.Submit("echo '%s'." % v)
y(x("I love Python"))
end program.

Regards,

Albert-Jan



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

All right, but apart from the sanitation, the medicine, education, wine, public order, irrigation, roads, a

fresh water system, and public health, what have the Romans ever done for us?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--------------------------------------------
On Thu, 1/16/14, Andy W <[hidden email]> wrote:

 Subject: Re: [SPSSX-L] Accessing a local macro value in an outside macro
 To: [hidden email]
 Date: Thursday, January 16, 2014, 2:40 PM

 Can someone give an example of using
 !EVAL when the expanded macro actually
 takes an argument? All examples I have been able to dig up
 are the macros
 which take no arguments (which I understand are useful for
 those hacky write
 an outfile meta programming thing - but doesn't translate to
 this
 situation).

 *********************************************.
 DEFINE !DashStr ( !POSITIONAL = !ENCLOSE("(",")") )
 !LET !D = !NULL
 !DO !j = 1 !TO !LENGTH(!1)
   !LET !D = !CONCAT(!D,"-")
 !DOEND
 !QUOTE(!D)
 !ENDDEFINE.

 DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
 !LET !A = !EVAL(!DashStr(!1)) .
 ECHO !QUOTE(!A).
 !ENDDEFINE.
 *This macro fails to compile - error message.
 *>In a macro expression, a left parenthesis immediately
 follows an operand.
 *>This command not executed.
 *********************************************.

 Here are a few more versions which compile as valid macro's,
 but when
 running produce a message "Running EVAL parameter 1
 COMMAN..." in the footer
 and just hang. After these I have to kill the SPSS process
 to even exit - so
 beware! So !EVAL doesn't appear be amenable to expanding a
 macro that takes
 arguments.

 *********************************************.
 DEFINE !DashStr ( !POSITIONAL = !TOKENS(1) )
 !LET !D = !NULL
 !DO !j = 1 !TO !LENGTH(!1)
   !LET !D = !CONCAT(!D,"-")
 !DOEND
 !QUOTE(!D)
 !ENDDEFINE.

 DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
 !LET !A = !EVAL(!DashStr) !1.
 ECHO !A.
 !ENDDEFINE.
 *This compiles, but when it runs it hangs forever expecting
 a command.
 *MarkTable 333.

 DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
 !LET !A = !EVAL(!DashStr) !EVAL(!1) .
 ECHO !A.
 !ENDDEFINE.
 *Ditto with prior.
 *MarkTable 333.
 *********************************************.






 -----
 Andy W
 [hidden email]
 http://andrewpwheeler.wordpress.com/
 --
 View this message in context: http://spssx-discussion.1045642.n5.nabble.com/Accessing-a-local-macro-value-in-an-outside-macro-tp5723922p5723933.html
 Sent from the SPSSX Discussion mailing list archive at
 Nabble.com.

 =====================
 To manage your subscription to SPSSX-L, send a message to
 [hidden email]
 (not to SPSSX-L), with no body text except the
 command. To leave the list, send the command
 SIGNOFF SPSSX-L
 For a list of commands to manage subscriptions, send the
 command
 INFO REFCARD

=====================
To manage your subscription to SPSSX-L, send a message to
[hidden email] (not to SPSSX-L), with no body text except the
command. To leave the list, send the command
SIGNOFF SPSSX-L
For a list of commands to manage subscriptions, send the command
INFO REFCARD
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Richard Ristow
In reply to this post by Andy W
At 08:40 AM 1/16/2014, Andy W wrote:

>Can someone give an example of using !EVAL when the expanded macro
>actually takes an argument?

I've written a little utility called !MacEcho, use to test and
display macro expansions:

*  Macro /* !MacEcho */ is used to display the macro expansion   .
DEFINE !MacEcho(!POS !NOEXPAND !CMDEND)
    ECHO  !QUOTE(!CONCAT('     Call  : ',!1)).
    ECHO  !QUOTE(!CONCAT('     Result: ',!EVAL(!1))).
!ENDDEFINE.


Here's an illustration, from some time past(*), where I used it to
pass a macro with an argument:


*  This is the test macro .......................................... .

DEFINE !Mystery(Help=!DEFAULT(No) !TOKENS(1))

   !IF (!UPCASE(!HELP) !NE Y) !THEN
      ECHO 'Sorry, it is a mystery. There is no help for you'.
   !IFEND

   !IF (!UPCASE(!HELP) !EQ Y) !THEN
      ECHO 'Yes! You can be helped! Mystery is solved!'.
   !IFEND
*.
!ENDDEFINE.

!MacEcho !Mystery  .
      Call  : !Mystery
      Result:  ECHO 'Sorry, it is a mystery. There is no help for you'
*

!MacEcho !MYSTERY Help=Y .
      Call  : !MYSTERY Help=Y
      Result:   ECHO 'Yes! You can be helped! Mystery is solved!'*
---------------------------------------------------------------
(*)  This is taken from posting
Date:    Sun, 25 Jun 2006 20:49:50 -0400
From:    Richard Ristow <[hidden email]>
Subject: Re: Macro expansion / Ultimate string parsing problem
To:      [hidden email]

X-ELNK-Info: spv=0;
X-ELNK-AV: 0
X-ELNK-Info: sbv=0; sbrc=.0; sbf=0b; sbw=000;

=====================
To manage your subscription to SPSSX-L, send a message to
[hidden email] (not to SPSSX-L), with no body text except the
command. To leave the list, send the command
SIGNOFF SPSSX-L
For a list of commands to manage subscriptions, send the command
INFO REFCARD
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Andy W
Albert,

You can feel free to assume I already know that you can replicate whatever functionality I am trying to accomplish in the MACRO facility in Python. The day has not yet come that I decide to write some simple code in Python over plain vanilla SPSS. I've already written the program I was interested in, at this point I'm just trying to learn about the macro facility and its limitations for future reference.

Richard,

Interesting, but I can't figure out how to apply it to my situation. This is just a very simple case of functional programming. Consider a macro called !F that takes one token within parentheses. Why is this valid:

!F(!Input)

And this is valid:

ECHO !F(!Input).

But this is not:

!LET !Output = !F(!Input)

The answer I've been getting is that when !F follows another macro "operand" like !LET, I need to use !EVAL to expand it. However, !EVAL only appears to expand a macro that takes no arguments (or has default arguments as you've shown). If I want to pass in an !Input and get an !Output I don't see how the example you've shown would allow me to accomplish that. The first example

!F(!Input)

Doesn't work, because whatever stuff it produces is only local. I can't hack !F to return stuff to the global environment nor will it allow you to change objects outside of its scope. Hence why I would like to assign what the function returns to an object. If you could do this it would allow you to basically make your own string manipulation functions in the macro facility, e.g. you could implement a more general !REPLACE function for string tokens.

Using some of the string manipulations Richard just shown as motivation, I came up with this.

**********************************************.
DEFINE !DashStr ( !POSITIONAL = !TOKENS(1) )
!LET !D = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !D = !CONCAT(!D,"-")
!DOEND
!D
!ENDDEFINE.

DEFINE !MarkTable ( !POSITIONAL = !CMDEND )
ECHO !QUOTE(!1).
!LET !A = !EVAL(!UNQUOTE("!DashStr !1"))
ECHO !QUOTE(!A).
!ENDDEFINE.
!MarkTable 3334.
**********************************************.

You will see with this though that !DashStr is expanded and correctly takes the next string as its argument, but !1 is unfortunately not expanded! That is, the result of when !DashStr !1 is called ends up being "--" because it pretends like !1 is a text input for the !DashStr macro instead of expanding !1 to be "3334". So close, but no cigar so far. I tried several other ways to make !1 expand as well (by nesting seperate !EVAL statements for !DashStr & !1 and trying to concatenate the two together) but was unable to get any to work.

Andy
Andy W
apwheele@gmail.com
http://andrewpwheeler.wordpress.com/
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Kirill Orlov
In reply to this post by Andy W
Andy,
In my experience, !EVAL() function scans its argument, and if the argument contains some macro call of another macro, the function runs (expands) it immediately. !EVAL is needed when the macro call is "hidden" in a string function or in a macro expression as its operand.

Example1.
!quote(!EVAL(!macrocall))
!EVAL is needed if you want !macrocall to expand inside !quote.

Example2.
!EVAL('!macrocall BlahBlah')
!EVAL is needed if you want !macrocall to expand inside quotes.

Example3.
!do !i !in (!EVAL(!macrocall))
!EVAL is needed if you want !macrocall to expand inside the expression.

Also, !EVAL is practically very useful to drop a trailing point and/or to cut out excessive spaces from a string. In this case, !EVAL can be used not only with macrocalls but with any strings.

Example4.
!EVAL("A       B C.")
returns string: A B C
Thus, !EVAL("A B C")=!EVAL("A      B C")=!EVAL("A B         C.") etc. which is handy.

Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Richard Ristow
In reply to this post by Andy W
At 02:17 PM 1/16/2014, Andy W wrote:

>Consider a macro called
>!F that takes one token within parentheses. Why is this valid:
>
>!F(!Input)
>
>And this is valid:
>
>ECHO !F(!Input).
>
>But this is not:
>
>!LET !Output = !F(!Input)
>
>!EVAL only appears to expand a macro that takes no arguments (or has
>default arguments as you've shown).

OK. To answer your last question first, !EVAL can indeed expand a
parametrized macro; see the *second* call in my last posting, where
it (correctly) expands the call
"!MYSTERY Help=Y". (I posted that for a reason!)

Second, you aren't asking about passing a macro with a parameter;
you're asking about *returning* a value *from* a macro. I didn't
answer this question at first, because you didn't ask it.

You're asking a macro to return a value, into the macro text. Macros
don't *return* values; they *generate* values, which go into the
(SPSS) code space. Normally, a macro doesn't 'see' what any macro is
calls generates; that has nothing to do with whether or not the
called macro takes parameters.

>I would like to assign what the function returns to an object. If
>you could do this it would allow you to basically make your own
>string manipulation functions in the macro facility, e.g. you could
>implement a more general !REPLACE function for string tokens.

Tell me about it. Tell any of us about it. Yes, it is (would be) very useful.

I'd taken for granted that this was impossible; that there was no way
to make a macro's generated text available to a calling macro.

I haven't time for a proper investigation now, but check David
Marso's postings. I thought that he'd found a way for a macro to
generate a value that gets assigned to a  variable belonging to a
calling macro, though if so, I can't find it at the moment. All I can
say is, (a) yes, it would be very useful; (b) it is *not* something
the macro facility is designed to offer; and (c) I'd expect David to
find a way, if anybody can.

But, again, it has nothing to do with how !EVAL works; it has to do
with how macro results are (not) passed back to the caller.

=====================
To manage your subscription to SPSSX-L, send a message to
[hidden email] (not to SPSSX-L), with no body text except the
command. To leave the list, send the command
SIGNOFF SPSSX-L
For a list of commands to manage subscriptions, send the command
INFO REFCARD
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Andy W
This is starting to remind me of dialogue in Alice in Wonderland. While I can accept the fate that what I want to do is impossible, I'm having a hard time understanding why the compiler is fine and dandy to accept

!F(!Input)

But

!LET !Output = !F(!Input)

is impossible. Where does !LET go if not "code space" - outer space? Rural Idaho? The moon? I type !LET in the syntax window the same as I do any other command.



Andy W
apwheele@gmail.com
http://andrewpwheeler.wordpress.com/
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Kirill Orlov
Andy,
Try this, to force macro at the right hand side of !LET.

define !F(!pos= !enclose('(',')'))
!conc('Andy ',!1)
!enddefine.

!F(Weeler).
*The F macro works.


define !MAIN()
!let !output= !F(Weeler)
echo !quote(!output).
!enddefine.

!MAIN.
*The F macro doesn't work correctly inside another macro when put in right hand side of macro expression.


define !MAIN()
!let !output= !eval('!F(Weeler)')
echo !quote(!output).
!enddefine.

!MAIN.
*But with the help of !EVAL and being put in apostrophes, it works allright.

17.01.2014 0:44, Andy W пишет:
This is starting to remind me of dialogue in Alice in Wonderland. While I can
accept the fate that what I want to do is impossible, I'm having a hard time
understanding why the compiler is fine and dandy to accept

!F(!Input)

But

!LET !Output = !F(!Input)

is impossible. Where does !LET go if not "code space" - outer space? Rural
Idaho? The moon? I type !LET in the syntax window the same as I do any other
command.







-----
Andy W
[hidden email]
http://andrewpwheeler.wordpress.com/
--
View this message in context: http://spssx-discussion.1045642.n5.nabble.com/Accessing-a-local-macro-value-in-an-outside-macro-tp5723922p5723952.html
Sent from the SPSSX Discussion mailing list archive at Nabble.com.

=====================
To manage your subscription to SPSSX-L, send a message to
[hidden email] (not to SPSSX-L), with no body text except the
command. To leave the list, send the command
SIGNOFF SPSSX-L
For a list of commands to manage subscriptions, send the command
INFO REFCARD




Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Richard Ristow
In reply to this post by Andy W
At 03:44 PM 1/16/2014, Andy W wrote:

>I'm having a hard time understanding why the compiler is fine and
>dandy to accept
>
>!F(!Input)
>
>But
>
>!LET !Output = !F(!Input)
>
>is impossible. Where does !LET go if not "code space" - outer
>space?  I type !LET in the syntax window the same as I do any other command.

The SPSS code space I was talking about is the stream of code that
the SPSS processor executes. It's what you get by expanding all the
macros in the original file.

Macros write to this code space -- that's what they're for. When you run

!F(!Input)

then whatever the macro emits is written to the code space. It is
*not* a value that's accessible in the macro space, i.e. to the same
or another macro.

If I write a really simple macro like

DEFINE !Freq1()
FREQUENCIES A.
!ENDDEFINE.

then "FREQUENCIES A." is the *output* of the macro, and goes to the
SPSS code space; it is not a *value* that can be returned to a
calling macro. And when you write

!LET !Output = !F(!Input)

you're expecting whatever !F produces to be text accessible to the
macro, so it can be assigned to a macro variable; but !F's output has
gone to the SPSS code space, or code stream, and the calling macro
has no access to it.

When you write

ECHO !F(!Input).

then ECHO is a native SPSS statement, not a macro statement; it's in
the SPSS code space, and it can 'see' the output of !F. !LET is in
the macro code space, and can't see anything any macro produces,
except macro variables defined in the same macro.

=====================
To manage your subscription to SPSSX-L, send a message to
[hidden email] (not to SPSSX-L), with no body text except the
command. To leave the list, send the command
SIGNOFF SPSSX-L
For a list of commands to manage subscriptions, send the command
INFO REFCARD
Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Kirill Orlov
Richard Ristow wrote:
And when you write
!LET !Output = !F(!Input)
 you're expecting whatever !F produces to be text accessible to the macro, so it can be assigned to a macro variable; but !F's output has gone to the SPSS code space, or code stream, and the calling macro has no access to it.

+1, Richard.
But it is possible to make the text !F() produces a value accessible to the parent macro via !EVAL + quoting, - as I've shown above.
!LET !Output = !EVAL('!F(!Input)')

Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Kirill Orlov
In reply to this post by Andy W
Andy,
Try also this.

define !F(!pos= !enclose('(',')'))
!conc('Andy ',!1)
!enddefine.

define !MAIN(!pos= !token(1))
!let !output= !eval(!conc('!F(',!1,')'))
echo !quote(!output).
!enddefine.

!MAIN Wheeler.
*Here, the argument "Wheeler" for the child macro is supplied by the parent macro.




Reply | Threaded
Open this post in threaded view
|

Re: Accessing a local macro value in an outside macro

Andy W
There we go! Thank you Kirill! (And everyone else for travelling down the rabbit hole with me).

!let !output= !eval('!F(!1)')

It treats "!1" like it is text and not a macro variable/pointer. But when you do

!let !output= !eval(!conc('!F(',!1,')'))

It points to !1 AND expands !F.

Here is an example that does the markdown tables but instead of having a macro replace the string with dashes it takes a second argument (and so you can replace it with any string you want). It should be obvious how you could use this to make your own REPLACE function in the macro parser if you wanted to.

*******************************************.
DEFINE !MarkTable ( !POSITIONAL = !CMDEND)
!LET !Stub = !HEAD(!1)
!LET !Header = !Stub
!LET !Align = !EVAL(!CONCAT("!REP ",!Stub," -"))
!DO !i !IN (!TAIL(!1))
  !LET !Stub = !CONCAT(!Stub," ",!QUOTE("|"),!i)
  !LET !Header = !CONCAT(!Header,"|",!i)
  !LET !Temp = !EVAL(!CONCAT("!REP ",!i," -"))
  !LET !Align = !CONCAT(!Align,"|",!Temp)
!DOEND
DO IF $casenum = 1.
  PRINT EJECT /!QUOTE(!Header) /!QUOTE(!Align).
END IF.
PRINT / !Stub.
!ENDDEFINE.

DEFINE !REP ( !POSITIONAL  = !TOKENS(1)
                       /!POSITIONAL = !TOKENS(1) )
!LET !A = !NULL
!DO !j = 1 !TO !LENGTH(!1)
  !LET !A = !CONCAT(!A,!2)
!DOEND
!A
!ENDDEFINE.

*Example Use.
DATASET CLOSE ALL.
DATA LIST FREE / Xa Ya (2F1.0) Za (A1).
BEGIN DATA
1 2 a
3 4 b
5 6 c
7 8 d
END DATA.
*SET MPRINT ON.
!MarkTable Xa Ya Za.
*SET MPRINT OFF.
EXECUTE.
********************************************.

Which then produces the output

Xa|Ya|Za
--|--|--
1 |2 |a
3 |4 |b
5 |6 |c
7 |8 |d
Andy W
apwheele@gmail.com
http://andrewpwheeler.wordpress.com/
12