<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: %let ignores semicolons in nested macro in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831367#M328509</link>
    <description>&lt;P&gt;Thank you, this is exactly the information I was looking for, clearly I haven't given much thought to macro compilation.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I concur that this is not exactly a highly productive design pattern, I figured it also doesn't&amp;nbsp;&lt;EM&gt;harm&lt;/EM&gt; to have it make no difference if the first statement gets executed or not. In my example all three statements are more or less the same, but in reality the second would be a data step, proc, library assignment... on which downstream statements rely. If the macro is then assigned to a macro variable even when it isn't designed that way (returning nothing of use to the macro processor), it'll still work.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Then again, it still breaks when nested, so it's indeed very limited in its usefulness - and in that sense perhaps even harmful if it gives the impression that the macro &lt;EM&gt;can&lt;/EM&gt; be used in macro variable assignment.&lt;/P&gt;</description>
    <pubDate>Thu, 01 Sep 2022 06:25:12 GMT</pubDate>
    <dc:creator>pblls</dc:creator>
    <dc:date>2022-09-01T06:25:12Z</dc:date>
    <item>
      <title>%let ignores semicolons in nested macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831247#M328465</link>
      <description>&lt;P&gt;This might not be a problem that absolutely needs solving, but it left me scratching my head &amp;amp; I'm wondering how I can prevent this.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;When I write a macro that executes actual statements (not just macro code), I often include a bogus option statement or even just a semicolon at the start - setting the page size to its current setting or so. The goal here is that if the macro were assigned via %let, the first statement would get gobbled but the rest of the code executes as normal (and you don't lose the first actually important statement inside the macro). As a simple example:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;options ps=100;
%MACRO PS;
   %do i = 1 %to 3;
      options ps=10&amp;amp;i;
      %put %sysfunc(getoption(ps, keyword));
   %end;
%MEND;

%let V1 = %PS;
%put &amp;amp;=V1;

PS=100
PS=102
PS=103
V1=options ps=101&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Notice that the first options statement never executes; it gets assigned to V1 instead. The other statements go through just fine, this is what I would expect.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;The issue is that when I do the same &lt;EM&gt;inside&lt;/EM&gt; a macro, the following happens (continuing the example):&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;%MACRO PS2;
   options ps=100;
   %let V2 = %PS;
   %put &amp;amp;=V2;
%MEND;

%PS2;

PS=100
PS=100
PS=100
V2=options ps=101;       options ps=102;       options ps=103;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Suddenly, %let gobbles &lt;STRONG&gt;all&lt;/STRONG&gt; statements from the inner macro, while macro code still executes as expected. This happens on all OSes/versions that I have available to me, it doesn't matter what the scope of the variable being assigned is, and no amount of %unquote at any level can stop this.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Again, not really a problem that needs fixing (rather to prevent a macro from breaking if it's being used function-style when in reality it isn't), but... what is going on here?&lt;/P&gt;</description>
      <pubDate>Wed, 31 Aug 2022 13:39:37 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831247#M328465</guid>
      <dc:creator>pblls</dc:creator>
      <dc:date>2022-08-31T13:39:37Z</dc:date>
    </item>
    <item>
      <title>Re: %let ignores semicolons in nested macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831272#M328468</link>
      <description>&lt;P&gt;Set Options mprint symbolgen; before running the macro and read the log. See if that gives you some idea what is happening.&lt;/P&gt;</description>
      <pubDate>Wed, 31 Aug 2022 14:45:02 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831272#M328468</guid>
      <dc:creator>ballardw</dc:creator>
      <dc:date>2022-08-31T14:45:02Z</dc:date>
    </item>
    <item>
      <title>Re: %let ignores semicolons in nested macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831275#M328471</link>
      <description>&lt;P&gt;Huh? You seem to using the word MACRO for both an actual macro and for a symbol (what most users call macro variables).&lt;/P&gt;
&lt;P&gt;Perhaps that confusion is part your problem?&lt;/P&gt;
&lt;P&gt;You define an actual macro with the %MACRO statement (definition ends with the %MEND statement).&amp;nbsp; You EXECUTE the macro by placing a % character in front of its name.&lt;/P&gt;
&lt;P&gt;You can define a macro variable using a %LET statement.&amp;nbsp; Everything between the equal sign and semicolon is the value to set to the macro variable.&amp;nbsp; To reference the value of a macro variable you place an &amp;amp; character in front of its name.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If you define a macro that generates one or more actual SAS statements then do not attempt to execute that macro in the middle of another statement, like the %LET macro statement.&amp;nbsp; Just execute it like you would any other statement.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%ps;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 31 Aug 2022 14:53:31 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831275#M328471</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2022-08-31T14:53:31Z</dc:date>
    </item>
    <item>
      <title>Re: %let ignores semicolons in nested macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831348#M328495</link>
      <description>&lt;P&gt;I would encourage you to re-think this idea of&amp;nbsp; adding a bogus statement to your macros.&amp;nbsp; I would be interested to see an example that shows the useful functionality you are trying to achieve.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In your first example:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;options ps=100;
%MACRO PS;
   %do i = 1 %to 3;
      options ps=10&amp;amp;i;
      %put %sysfunc(getoption(ps, keyword));
   %end;
%MEND;

%let V1 = %PS;
%put &amp;amp;=V1;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;When you invoke the macro %PS it will generate 3 options statements, and execute 3 %PUT statements.&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;When you invoke %PS on the right had side of a %LET statement (it's not clear why you would want to do this), you generate:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let V1 = options ps=101; options ps=102; options ps=103;;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;So the text for first the first options statement is assigned to the macro variable V1 because the first semicolon generated by the macro PS ends the %LET statement.&amp;nbsp;The second two options statements will be executed by SAS.&amp;nbsp; Note there is an extra semicolon at the end. This "works" (i.e. runs without errors), but I don't see how adding the OPTIONS statement has added any functionality.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Now look at your second example:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%MACRO PS2;
   options ps=100;
   %let V2 = %PS;
   %put &amp;amp;=V2;
%MEND;

%PS2;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;When the macro PS2 compiles, the %LET statement is compiled. The semicolon inside of the macro definition ends the %LET statement. The macro invocation of %PS has not been executed.&amp;nbsp; Thus the %LET statement compiles as something like: %let V2= whatever text results from invoking the macro PS ;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;When you call %PS2, the precompiled %LET statement executes, and %PS resolves to:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;options ps=101; options ps=102; options ps=103;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Note that those semicolons generated by %PS cannot end the %LET statement, because the %LET statement was already ended when the macro was compiled.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The difference you have illustrated is not a problem or bug, it's a result of the way that SAS compiles macros.&amp;nbsp; It is an instructive example, to help think about how the macro language works.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But to the big picture, I don't think you're accomplishing any useful functionality with this approach, and I expect it will be confusing to anyone who inherits such code.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 01 Sep 2022 00:21:24 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831348#M328495</guid>
      <dc:creator>Quentin</dc:creator>
      <dc:date>2022-09-01T00:21:24Z</dc:date>
    </item>
    <item>
      <title>Re: %let ignores semicolons in nested macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831367#M328509</link>
      <description>&lt;P&gt;Thank you, this is exactly the information I was looking for, clearly I haven't given much thought to macro compilation.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I concur that this is not exactly a highly productive design pattern, I figured it also doesn't&amp;nbsp;&lt;EM&gt;harm&lt;/EM&gt; to have it make no difference if the first statement gets executed or not. In my example all three statements are more or less the same, but in reality the second would be a data step, proc, library assignment... on which downstream statements rely. If the macro is then assigned to a macro variable even when it isn't designed that way (returning nothing of use to the macro processor), it'll still work.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Then again, it still breaks when nested, so it's indeed very limited in its usefulness - and in that sense perhaps even harmful if it gives the impression that the macro &lt;EM&gt;can&lt;/EM&gt; be used in macro variable assignment.&lt;/P&gt;</description>
      <pubDate>Thu, 01 Sep 2022 06:25:12 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831367#M328509</guid>
      <dc:creator>pblls</dc:creator>
      <dc:date>2022-09-01T06:25:12Z</dc:date>
    </item>
    <item>
      <title>Re: %let ignores semicolons in nested macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831496#M328589</link>
      <description>&lt;P&gt;If you want to capture all of the text that the macro emits you could just enclose the macro call in quotes.&lt;/P&gt;
&lt;PRE&gt;7    %macro two_statements;
8      x=1;
9      y=x*x;
10   %mend;
11
12   %put "%two_statements" ;
"x=1;   y=x*x;"

&lt;/PRE&gt;
&lt;P&gt;But that really just converts the problem caused by a macro that generates semicolons to a problem with a macro that generates double quote characters.&amp;nbsp; In which case you might want to use a data step and RESOLVE() function instead.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want;
  length string $200;
  string=resolve('%two_statements');
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Sat, 03 Sep 2022 03:11:05 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/let-ignores-semicolons-in-nested-macro/m-p/831496#M328589</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2022-09-03T03:11:05Z</dc:date>
    </item>
  </channel>
</rss>

