<?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 A SAS Macro to Extend the SAS/IML Print Function in SAS/IML Software and Matrix Computations</title>
    <link>https://communities.sas.com/t5/SAS-IML-Software-and-Matrix/A-SAS-Macro-to-Extend-the-SAS-IML-Print-Function/m-p/857893#M5958</link>
    <description>&lt;P&gt;I have written a SAS macro to extend the SAS/IML PRINT function. It maintains the syntax of the PRINT function and adds the IML RESET options as modifiers to the PRINT environment. The code is:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro PRINTIML( ARG )/ parmbuff ;

   /* PURPOSE: enhance SAS/IML PRINT statement with additional capabilities
    *
    * NOTE:    must use same SAS/IML syntax in %PRINTIML macro as in SAS/IML PRINT statement
    *
    * NOTE:    must use backslash (\) after &amp;amp;ARG to indicate RESET settings to be applied to SAS/IML PRINT statement
    *          delimiter that separates SAS/IML PRINT statement options from RESET options is backslash (\)
    *
    * NOTE:    default values for RESET are: noautoname nocenter fw=9 noname spaces=1
    *
    * NOTE:    after printing, any specified RESET settings are restored to default values,
    *          regardless of former settings (simplistic approach due to inability to know
    *          value of RESET setting prior to invocation of %PRINTIML macro)
    *
    * SYNTAX:  %PRINTIML( &amp;lt;matrices&amp;gt; &amp;lt;( expression )&amp;gt; &amp;lt;"message"&amp;gt; &amp;lt;pointer controls&amp;gt; &amp;lt;[options]&amp;gt; \ &amp;lt;RESET Options&amp;gt; )
    *
    * EXAMPLES OF USE:
    *    proc iml ;
    *
    *       a = { 1 2 3, 4 5 6 } ;
    *       b = { 6 5 4, 3 2 1 } ;
    *
    *       r_name = { 'row 1', 'row 2' } ;
    *
    *       %PRINTIML( (( a + b )/ 7 ) \ center autoname spaces=3 fw=2 )
    *       %PRINTIML( ( a[ 1, ] ) ( b[ , 1 ] ) \ center autoname spaces=3 fw=2 )
    *       %PRINTIML( ( a + b )[ rowname=r_name format=10.5 ] \ spaces=1 )
    *       %PRINTIML( a , b / ( a + b ) \ spaces=1 )
    *    quit ;
    */

   %local I ;

   /* verify that PROC IML is licensed for use */

   %if not %sysprod(IML)
   %then %do ;
      %put /-----------------------------------------------\ ;
      %put | ERROR: PROC IML not licensed for your system. | ;
      %put | Terminating macro %PRINTIML forthwith.        | ;
      %put \-----------------------------------------------/ ;
   
      %goto L9999 ;
   %end ;

   /*############################################################################*/
   /* begin macro execution
   /*############################################################################*/

   %let AUTONAME = noautoname ;
   %let CENTER   = nocenter ;
   %let FW       = ;
   %let NAME     = noname ;
   %let SPACES   = %str( spaces=1 ) ;

   /*============================================================================*/
   /* remove left, right parens from &amp;amp;SYSPBUFF
   /* find start location of RESET options, if any (backslash indicates that RESET options follow)
   /*
   /* note: spaces in %bquote fcn are included in result, e.g., %bquote( A B C ) ne %bquote(A B C)
   /*
   /* note: must check for case when no RESET settings present
   /*============================================================================*/

   %let STRING  = %qsubstr( %bquote(&amp;amp;SYSPBUFF), 2, %length(&amp;amp;SYSPBUFF) - 2 ) ;
   %let STRING  = %qleft(%qtrim(&amp;amp;STRING)) ;

   %let STRING1 = %qsysfunc( reverse( &amp;amp;STRING )) ;

   %let NDX     = %index( &amp;amp;STRING1, %str(\)) ;

   /*============================================================================*/
   /* extract RESET settings from reversed string, reverse again to create original order,
   /* check for presence of settings. if none, set &amp;amp;NDX = 0 to prevent further action
   /*============================================================================*/

   %if &amp;amp;NDX &amp;gt; 0
   %then %do ;
      %let SETTINGS = %qupcase( %qsubstr( %bquote(&amp;amp;STRING1), 1, &amp;amp;NDX - 1 )) ;

      %let SETTINGS = %qsysfunc( reverse( &amp;amp;SETTINGS )) ;

      /* if any complex expression closing character, e.g., ) ] }, found, no settings used.
       * reset &amp;amp;NDX flag to prevent further parsing for settings
       */

      %if %eval( %index( &amp;amp;SETTINGS, %str(%))) + %index( &amp;amp;SETTINGS, ] ) + %index( &amp;amp;SETTINGS, } )) &amp;gt; 0
      %then %let NDX = 0 ;

      /* extract expression(s) to be printed from reversed string
       * reverse again to restore original order
       */

      %let STRING = %qsubstr( &amp;amp;STRING1, &amp;amp;NDX + 1 ) ;
      %let STRING = %qsysfunc( reverse( &amp;amp;STRING )) ;
   %end ;

   /*============================================================================*/
   /* insert blank around '[', '/', '(', ')', ',' to distinguish potential options
   /*============================================================================*/

   %let BUFFER = ;

   %do I = 1 %to %length( &amp;amp;STRING ) ;
      %let STRING1 = %qsubstr( &amp;amp;STRING, &amp;amp;I, 1 ) ;

      %if &amp;amp;STRING1 = [
       or &amp;amp;STRING1 = %str(/)
       or &amp;amp;STRING1 = %str(%()
       or &amp;amp;STRING1 = %str(%))
       or &amp;amp;STRING1 = %str(,)
      %then %let BUFFER = &amp;amp;BUFFER%str( &amp;amp;STRING1 ) ; %else %let BUFFER = &amp;amp;BUFFER.&amp;amp;STRING1 ;
   %end ;

   %let STRING = &amp;amp;BUFFER ;

   /*============================================================================*/
   /* create argument for SAS/IML PRINT statement
   /*    simple expressions, e.g., variable name, not enclosed in parentheses
   /*    complex expressions, e.g., ( a + b / c * d[ +, 1] ), must be enclosed in () pairs
   /*    options            , e.g., [ format=10.5 ]         , must be enclosed in [] pairs
   /*============================================================================*/

   %let NBKT   = 0 ;
   %let NPAR   = 0 ;
   %let NSTR   = 0 ;

   %let I         = 1 ;
   %let TOKEN1    = %qscan( %bquote(&amp;amp;STRING), &amp;amp;I, %str( )) ;

   %do %until( &amp;amp;&amp;amp;TOKEN&amp;amp;I = ) ;

      /*----------------------------------------------------------------------------*/
      /* create macro vars to indicate presence/absence of (), []. set counters.
      /*----------------------------------------------------------------------------*/

      %let TOKEN_1 = %qsubstr( &amp;amp;&amp;amp;TOKEN&amp;amp;I,                    1, 1 ) ;
      %let TOKEN_2 = %qsubstr( &amp;amp;&amp;amp;TOKEN&amp;amp;I, %length( &amp;amp;&amp;amp;TOKEN&amp;amp;I ), 1 ) ;

      /* process brackets */

      %let LBKT&amp;amp;I = %eval( %index( &amp;amp;&amp;amp;TOKEN&amp;amp;I, [ ) &amp;gt; 0 ) ;
      %let RBKT&amp;amp;I = %eval( %index( &amp;amp;&amp;amp;TOKEN&amp;amp;I, ] ) &amp;gt; 0 ) ;

      %let NBKT   = %eval( &amp;amp;NBKT + &amp;amp;&amp;amp;LBKT&amp;amp;I - &amp;amp;&amp;amp;RBKT&amp;amp;I ) ;
      %let NBKT&amp;amp;I = %eval( &amp;amp;NBKT + &amp;amp;&amp;amp;RBKT&amp;amp;I             ) ;

      /* process parentheses */

      %let LPAR&amp;amp;I = %eval( %index( &amp;amp;&amp;amp;TOKEN&amp;amp;I, %str(%() ) &amp;gt; 0 ) ;
      %let RPAR&amp;amp;I = %eval( %index( &amp;amp;&amp;amp;TOKEN&amp;amp;I, %str(%)) ) &amp;gt; 0 ) ;

      %let NPAR       = %eval( &amp;amp;NPAR + &amp;amp;&amp;amp;LPAR&amp;amp;I - &amp;amp;&amp;amp;RPAR&amp;amp;I ) ;
      %let NPAR&amp;amp;I     = %eval( &amp;amp;NPAR + &amp;amp;&amp;amp;RPAR&amp;amp;I            ) ;

      %let EXPR_END&amp;amp;I = %eval( &amp;amp;&amp;amp;NPAR&amp;amp;I = 1 and &amp;amp;NPAR = 0  ) ;

      /* process string quotes */

      %let LSTR&amp;amp;I = %eval( &amp;amp;TOKEN_1 = %str(%') or &amp;amp;TOKEN_1 = %str(%")) ;
      %let RSTR&amp;amp;I = %eval( &amp;amp;TOKEN_2 = %str(%') or &amp;amp;TOKEN_2 = %str(%")) ;

      %let NSTR   = %eval( &amp;amp;NSTR + &amp;amp;&amp;amp;LSTR&amp;amp;I - &amp;amp;&amp;amp;RSTR&amp;amp;I ) ;
      %let NSTR&amp;amp;I = %eval( &amp;amp;NSTR + &amp;amp;&amp;amp;RSTR&amp;amp;I            ) ;

      %let I = %eval( &amp;amp;I + 1 ) ;
      %let TOKEN&amp;amp;I = %qscan( &amp;amp;STRING, &amp;amp;I, %str( )) ;
   %end ;

   %let N_TOKEN = %eval( &amp;amp;I - 1 ) ;

   /*============================================================================*/
   /* assemble 3 cases:
   /*    simple expression  # paren = 0
   /*    string expression  # paren = 0, # strings &amp;gt; 0
   /*    complex expression # paren &amp;gt; 0, # strings &amp;gt; 0, # brackets &amp;gt; 0
   /*============================================================================*/

   %let BUFFER = ;
   %let TOKEN  = ;

   %do I = 1 %to &amp;amp;N_TOKEN ;

      %if &amp;amp;&amp;amp;NPAR&amp;amp;I = 0 and &amp;amp;&amp;amp;NSTR&amp;amp;I = 0 and &amp;amp;&amp;amp;NBKT&amp;amp;I = 0 /* i.e., outside of (expression) */
      %then %do ;
         %if &amp;amp;&amp;amp;TOKEN&amp;amp;I ne %str(,) and &amp;amp;&amp;amp;TOKEN&amp;amp;I ne %str(/)
         %then %let BUFFER = &amp;amp;BUFFER " &amp;amp;&amp;amp;TOKEN&amp;amp;I = " &amp;amp;&amp;amp;TOKEN&amp;amp;I ;
         %else %let BUFFER = &amp;amp;BUFFER.%str( &amp;amp;&amp;amp;TOKEN&amp;amp;I ) ;
      %end ;
      %else
      %if &amp;amp;&amp;amp;NPAR&amp;amp;I = 0 and ( &amp;amp;&amp;amp;NSTR&amp;amp;I &amp;gt; 0 or &amp;amp;&amp;amp;NBKT&amp;amp;I &amp;gt; 0 ) /* 'message' or [options] but not (expression) */
      %then %do ;
         %let BUFFER = &amp;amp;BUFFER &amp;amp;&amp;amp;TOKEN&amp;amp;I ;
      %end ;
      %else %do ;
         %let TOKEN = &amp;amp;TOKEN.&amp;amp;&amp;amp;TOKEN&amp;amp;I ; /* build (expression) */

         %if &amp;amp;&amp;amp;EXPR_END&amp;amp;I /* have built (expression), put to output buffer */
         %then %do ;
            %let BUFFER = &amp;amp;BUFFER " &amp;amp;TOKEN. = " &amp;amp;TOKEN ;
            %let TOKEN  = ;
         %end ;
      %end ;
   %end ;

   /*============================================================================*/
   /* if settings follow &amp;amp;ARG, parse them from &amp;amp;SYSPBUFF and apply them
   /*============================================================================*/

   %if &amp;amp;NDX &amp;gt; 0
   %then %do ;
      %let I = 1 ;
      %let TOKEN = %scan( &amp;amp;SETTINGS, 1, %str( )) ;

      %do %while( %length( &amp;amp;TOKEN ) &amp;gt; 0 ) ;
         %if &amp;amp;TOKEN                  = AUTONAME %then %let AUTONAME = autoname ;
         %if &amp;amp;TOKEN                  = CENTER   %then %let CENTER   = center ;
         %if %substr( &amp;amp;TOKEN, 1, 2 ) = FW       %then %let FW       = &amp;amp;TOKEN ;
         %if &amp;amp;TOKEN                  = NAME     %then %let NAME     = name ;
         %if %substr( &amp;amp;TOKEN, 1, 2 ) = SP       %then %let SPACES   = &amp;amp;TOKEN ;

         %let I = %eval( &amp;amp;I + 1 ) ;
         %let TOKEN = %scan( &amp;amp;SETTINGS, &amp;amp;I, %str( )) ;
      %end ;
   %end ;   

   reset &amp;amp;AUTONAME &amp;amp;CENTER &amp;amp;FW &amp;amp;NAME &amp;amp;SPACES ;

   /* resolve SAS/IML PRINT statement */

   print %unquote(&amp;amp;BUFFER) ;

   /*============================================================================*/
   /* invert settings, if any
   /*============================================================================*/

   %if &amp;amp;NDX &amp;gt; 0
   %then %do ;
      %if &amp;amp;AUTONAME ne %then %let AUTONAME = noautoname ;
      %if &amp;amp;CENTER   ne %then %let CENTER   = nocenter ;
      %if &amp;amp;FW       ne %then %let FW       = %str( FW=9 ) ;
      %if &amp;amp;NAME     ne %then %let NAME     = noname ;
      %if &amp;amp;SPACES   ne %then %let SPACES   = %str( SPACES=1 ) ;

      reset &amp;amp;AUTONAME &amp;amp;CENTER &amp;amp;FW &amp;amp;NAME &amp;amp;SPACES ;
   %end ;

%L9999:
%mend PRINTIML ;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;and the results of executing the examples of use in the macro prologue are demonstrated below:&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;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;                           ((a+b)/7) =     1  1  1
                                           1  1  1


                  (a[1,]) =     1  2  3    (b[,1]) =     6
                                                         3


 (a+b) =  row 1    7.00000    7.00000    7.00000
          row 2    7.00000    7.00000    7.00000


 a =          1         2         3
              4         5         6
 b =          6         5         4
              3         2         1
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&lt;CODE class=" language-sas"&gt;Perhaps you will find it useful.
&lt;/CODE&gt;&lt;CODE class=" language-sas"&gt;&lt;/CODE&gt;&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>Wed, 08 Feb 2023 21:12:55 GMT</pubDate>
    <dc:creator>rbettinger</dc:creator>
    <dc:date>2023-02-08T21:12:55Z</dc:date>
    <item>
      <title>A SAS Macro to Extend the SAS/IML Print Function</title>
      <link>https://communities.sas.com/t5/SAS-IML-Software-and-Matrix/A-SAS-Macro-to-Extend-the-SAS-IML-Print-Function/m-p/857893#M5958</link>
      <description>&lt;P&gt;I have written a SAS macro to extend the SAS/IML PRINT function. It maintains the syntax of the PRINT function and adds the IML RESET options as modifiers to the PRINT environment. The code is:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro PRINTIML( ARG )/ parmbuff ;

   /* PURPOSE: enhance SAS/IML PRINT statement with additional capabilities
    *
    * NOTE:    must use same SAS/IML syntax in %PRINTIML macro as in SAS/IML PRINT statement
    *
    * NOTE:    must use backslash (\) after &amp;amp;ARG to indicate RESET settings to be applied to SAS/IML PRINT statement
    *          delimiter that separates SAS/IML PRINT statement options from RESET options is backslash (\)
    *
    * NOTE:    default values for RESET are: noautoname nocenter fw=9 noname spaces=1
    *
    * NOTE:    after printing, any specified RESET settings are restored to default values,
    *          regardless of former settings (simplistic approach due to inability to know
    *          value of RESET setting prior to invocation of %PRINTIML macro)
    *
    * SYNTAX:  %PRINTIML( &amp;lt;matrices&amp;gt; &amp;lt;( expression )&amp;gt; &amp;lt;"message"&amp;gt; &amp;lt;pointer controls&amp;gt; &amp;lt;[options]&amp;gt; \ &amp;lt;RESET Options&amp;gt; )
    *
    * EXAMPLES OF USE:
    *    proc iml ;
    *
    *       a = { 1 2 3, 4 5 6 } ;
    *       b = { 6 5 4, 3 2 1 } ;
    *
    *       r_name = { 'row 1', 'row 2' } ;
    *
    *       %PRINTIML( (( a + b )/ 7 ) \ center autoname spaces=3 fw=2 )
    *       %PRINTIML( ( a[ 1, ] ) ( b[ , 1 ] ) \ center autoname spaces=3 fw=2 )
    *       %PRINTIML( ( a + b )[ rowname=r_name format=10.5 ] \ spaces=1 )
    *       %PRINTIML( a , b / ( a + b ) \ spaces=1 )
    *    quit ;
    */

   %local I ;

   /* verify that PROC IML is licensed for use */

   %if not %sysprod(IML)
   %then %do ;
      %put /-----------------------------------------------\ ;
      %put | ERROR: PROC IML not licensed for your system. | ;
      %put | Terminating macro %PRINTIML forthwith.        | ;
      %put \-----------------------------------------------/ ;
   
      %goto L9999 ;
   %end ;

   /*############################################################################*/
   /* begin macro execution
   /*############################################################################*/

   %let AUTONAME = noautoname ;
   %let CENTER   = nocenter ;
   %let FW       = ;
   %let NAME     = noname ;
   %let SPACES   = %str( spaces=1 ) ;

   /*============================================================================*/
   /* remove left, right parens from &amp;amp;SYSPBUFF
   /* find start location of RESET options, if any (backslash indicates that RESET options follow)
   /*
   /* note: spaces in %bquote fcn are included in result, e.g., %bquote( A B C ) ne %bquote(A B C)
   /*
   /* note: must check for case when no RESET settings present
   /*============================================================================*/

   %let STRING  = %qsubstr( %bquote(&amp;amp;SYSPBUFF), 2, %length(&amp;amp;SYSPBUFF) - 2 ) ;
   %let STRING  = %qleft(%qtrim(&amp;amp;STRING)) ;

   %let STRING1 = %qsysfunc( reverse( &amp;amp;STRING )) ;

   %let NDX     = %index( &amp;amp;STRING1, %str(\)) ;

   /*============================================================================*/
   /* extract RESET settings from reversed string, reverse again to create original order,
   /* check for presence of settings. if none, set &amp;amp;NDX = 0 to prevent further action
   /*============================================================================*/

   %if &amp;amp;NDX &amp;gt; 0
   %then %do ;
      %let SETTINGS = %qupcase( %qsubstr( %bquote(&amp;amp;STRING1), 1, &amp;amp;NDX - 1 )) ;

      %let SETTINGS = %qsysfunc( reverse( &amp;amp;SETTINGS )) ;

      /* if any complex expression closing character, e.g., ) ] }, found, no settings used.
       * reset &amp;amp;NDX flag to prevent further parsing for settings
       */

      %if %eval( %index( &amp;amp;SETTINGS, %str(%))) + %index( &amp;amp;SETTINGS, ] ) + %index( &amp;amp;SETTINGS, } )) &amp;gt; 0
      %then %let NDX = 0 ;

      /* extract expression(s) to be printed from reversed string
       * reverse again to restore original order
       */

      %let STRING = %qsubstr( &amp;amp;STRING1, &amp;amp;NDX + 1 ) ;
      %let STRING = %qsysfunc( reverse( &amp;amp;STRING )) ;
   %end ;

   /*============================================================================*/
   /* insert blank around '[', '/', '(', ')', ',' to distinguish potential options
   /*============================================================================*/

   %let BUFFER = ;

   %do I = 1 %to %length( &amp;amp;STRING ) ;
      %let STRING1 = %qsubstr( &amp;amp;STRING, &amp;amp;I, 1 ) ;

      %if &amp;amp;STRING1 = [
       or &amp;amp;STRING1 = %str(/)
       or &amp;amp;STRING1 = %str(%()
       or &amp;amp;STRING1 = %str(%))
       or &amp;amp;STRING1 = %str(,)
      %then %let BUFFER = &amp;amp;BUFFER%str( &amp;amp;STRING1 ) ; %else %let BUFFER = &amp;amp;BUFFER.&amp;amp;STRING1 ;
   %end ;

   %let STRING = &amp;amp;BUFFER ;

   /*============================================================================*/
   /* create argument for SAS/IML PRINT statement
   /*    simple expressions, e.g., variable name, not enclosed in parentheses
   /*    complex expressions, e.g., ( a + b / c * d[ +, 1] ), must be enclosed in () pairs
   /*    options            , e.g., [ format=10.5 ]         , must be enclosed in [] pairs
   /*============================================================================*/

   %let NBKT   = 0 ;
   %let NPAR   = 0 ;
   %let NSTR   = 0 ;

   %let I         = 1 ;
   %let TOKEN1    = %qscan( %bquote(&amp;amp;STRING), &amp;amp;I, %str( )) ;

   %do %until( &amp;amp;&amp;amp;TOKEN&amp;amp;I = ) ;

      /*----------------------------------------------------------------------------*/
      /* create macro vars to indicate presence/absence of (), []. set counters.
      /*----------------------------------------------------------------------------*/

      %let TOKEN_1 = %qsubstr( &amp;amp;&amp;amp;TOKEN&amp;amp;I,                    1, 1 ) ;
      %let TOKEN_2 = %qsubstr( &amp;amp;&amp;amp;TOKEN&amp;amp;I, %length( &amp;amp;&amp;amp;TOKEN&amp;amp;I ), 1 ) ;

      /* process brackets */

      %let LBKT&amp;amp;I = %eval( %index( &amp;amp;&amp;amp;TOKEN&amp;amp;I, [ ) &amp;gt; 0 ) ;
      %let RBKT&amp;amp;I = %eval( %index( &amp;amp;&amp;amp;TOKEN&amp;amp;I, ] ) &amp;gt; 0 ) ;

      %let NBKT   = %eval( &amp;amp;NBKT + &amp;amp;&amp;amp;LBKT&amp;amp;I - &amp;amp;&amp;amp;RBKT&amp;amp;I ) ;
      %let NBKT&amp;amp;I = %eval( &amp;amp;NBKT + &amp;amp;&amp;amp;RBKT&amp;amp;I             ) ;

      /* process parentheses */

      %let LPAR&amp;amp;I = %eval( %index( &amp;amp;&amp;amp;TOKEN&amp;amp;I, %str(%() ) &amp;gt; 0 ) ;
      %let RPAR&amp;amp;I = %eval( %index( &amp;amp;&amp;amp;TOKEN&amp;amp;I, %str(%)) ) &amp;gt; 0 ) ;

      %let NPAR       = %eval( &amp;amp;NPAR + &amp;amp;&amp;amp;LPAR&amp;amp;I - &amp;amp;&amp;amp;RPAR&amp;amp;I ) ;
      %let NPAR&amp;amp;I     = %eval( &amp;amp;NPAR + &amp;amp;&amp;amp;RPAR&amp;amp;I            ) ;

      %let EXPR_END&amp;amp;I = %eval( &amp;amp;&amp;amp;NPAR&amp;amp;I = 1 and &amp;amp;NPAR = 0  ) ;

      /* process string quotes */

      %let LSTR&amp;amp;I = %eval( &amp;amp;TOKEN_1 = %str(%') or &amp;amp;TOKEN_1 = %str(%")) ;
      %let RSTR&amp;amp;I = %eval( &amp;amp;TOKEN_2 = %str(%') or &amp;amp;TOKEN_2 = %str(%")) ;

      %let NSTR   = %eval( &amp;amp;NSTR + &amp;amp;&amp;amp;LSTR&amp;amp;I - &amp;amp;&amp;amp;RSTR&amp;amp;I ) ;
      %let NSTR&amp;amp;I = %eval( &amp;amp;NSTR + &amp;amp;&amp;amp;RSTR&amp;amp;I            ) ;

      %let I = %eval( &amp;amp;I + 1 ) ;
      %let TOKEN&amp;amp;I = %qscan( &amp;amp;STRING, &amp;amp;I, %str( )) ;
   %end ;

   %let N_TOKEN = %eval( &amp;amp;I - 1 ) ;

   /*============================================================================*/
   /* assemble 3 cases:
   /*    simple expression  # paren = 0
   /*    string expression  # paren = 0, # strings &amp;gt; 0
   /*    complex expression # paren &amp;gt; 0, # strings &amp;gt; 0, # brackets &amp;gt; 0
   /*============================================================================*/

   %let BUFFER = ;
   %let TOKEN  = ;

   %do I = 1 %to &amp;amp;N_TOKEN ;

      %if &amp;amp;&amp;amp;NPAR&amp;amp;I = 0 and &amp;amp;&amp;amp;NSTR&amp;amp;I = 0 and &amp;amp;&amp;amp;NBKT&amp;amp;I = 0 /* i.e., outside of (expression) */
      %then %do ;
         %if &amp;amp;&amp;amp;TOKEN&amp;amp;I ne %str(,) and &amp;amp;&amp;amp;TOKEN&amp;amp;I ne %str(/)
         %then %let BUFFER = &amp;amp;BUFFER " &amp;amp;&amp;amp;TOKEN&amp;amp;I = " &amp;amp;&amp;amp;TOKEN&amp;amp;I ;
         %else %let BUFFER = &amp;amp;BUFFER.%str( &amp;amp;&amp;amp;TOKEN&amp;amp;I ) ;
      %end ;
      %else
      %if &amp;amp;&amp;amp;NPAR&amp;amp;I = 0 and ( &amp;amp;&amp;amp;NSTR&amp;amp;I &amp;gt; 0 or &amp;amp;&amp;amp;NBKT&amp;amp;I &amp;gt; 0 ) /* 'message' or [options] but not (expression) */
      %then %do ;
         %let BUFFER = &amp;amp;BUFFER &amp;amp;&amp;amp;TOKEN&amp;amp;I ;
      %end ;
      %else %do ;
         %let TOKEN = &amp;amp;TOKEN.&amp;amp;&amp;amp;TOKEN&amp;amp;I ; /* build (expression) */

         %if &amp;amp;&amp;amp;EXPR_END&amp;amp;I /* have built (expression), put to output buffer */
         %then %do ;
            %let BUFFER = &amp;amp;BUFFER " &amp;amp;TOKEN. = " &amp;amp;TOKEN ;
            %let TOKEN  = ;
         %end ;
      %end ;
   %end ;

   /*============================================================================*/
   /* if settings follow &amp;amp;ARG, parse them from &amp;amp;SYSPBUFF and apply them
   /*============================================================================*/

   %if &amp;amp;NDX &amp;gt; 0
   %then %do ;
      %let I = 1 ;
      %let TOKEN = %scan( &amp;amp;SETTINGS, 1, %str( )) ;

      %do %while( %length( &amp;amp;TOKEN ) &amp;gt; 0 ) ;
         %if &amp;amp;TOKEN                  = AUTONAME %then %let AUTONAME = autoname ;
         %if &amp;amp;TOKEN                  = CENTER   %then %let CENTER   = center ;
         %if %substr( &amp;amp;TOKEN, 1, 2 ) = FW       %then %let FW       = &amp;amp;TOKEN ;
         %if &amp;amp;TOKEN                  = NAME     %then %let NAME     = name ;
         %if %substr( &amp;amp;TOKEN, 1, 2 ) = SP       %then %let SPACES   = &amp;amp;TOKEN ;

         %let I = %eval( &amp;amp;I + 1 ) ;
         %let TOKEN = %scan( &amp;amp;SETTINGS, &amp;amp;I, %str( )) ;
      %end ;
   %end ;   

   reset &amp;amp;AUTONAME &amp;amp;CENTER &amp;amp;FW &amp;amp;NAME &amp;amp;SPACES ;

   /* resolve SAS/IML PRINT statement */

   print %unquote(&amp;amp;BUFFER) ;

   /*============================================================================*/
   /* invert settings, if any
   /*============================================================================*/

   %if &amp;amp;NDX &amp;gt; 0
   %then %do ;
      %if &amp;amp;AUTONAME ne %then %let AUTONAME = noautoname ;
      %if &amp;amp;CENTER   ne %then %let CENTER   = nocenter ;
      %if &amp;amp;FW       ne %then %let FW       = %str( FW=9 ) ;
      %if &amp;amp;NAME     ne %then %let NAME     = noname ;
      %if &amp;amp;SPACES   ne %then %let SPACES   = %str( SPACES=1 ) ;

      reset &amp;amp;AUTONAME &amp;amp;CENTER &amp;amp;FW &amp;amp;NAME &amp;amp;SPACES ;
   %end ;

%L9999:
%mend PRINTIML ;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;and the results of executing the examples of use in the macro prologue are demonstrated below:&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;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;                           ((a+b)/7) =     1  1  1
                                           1  1  1


                  (a[1,]) =     1  2  3    (b[,1]) =     6
                                                         3


 (a+b) =  row 1    7.00000    7.00000    7.00000
          row 2    7.00000    7.00000    7.00000


 a =          1         2         3
              4         5         6
 b =          6         5         4
              3         2         1
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&lt;CODE class=" language-sas"&gt;Perhaps you will find it useful.
&lt;/CODE&gt;&lt;CODE class=" language-sas"&gt;&lt;/CODE&gt;&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>Wed, 08 Feb 2023 21:12:55 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-IML-Software-and-Matrix/A-SAS-Macro-to-Extend-the-SAS-IML-Print-Function/m-p/857893#M5958</guid>
      <dc:creator>rbettinger</dc:creator>
      <dc:date>2023-02-08T21:12:55Z</dc:date>
    </item>
  </channel>
</rss>

