SyntaxHighlighter

Monday, October 13, 2014

Code Formatter

In July 2010, Chris Hemedinger author of The SAS Dummy blog wrote an article titled 'Hope for ugly programs'.

That article showed that SAS Enterprise Guide had a shortcut of Ctrl-I ("indent this!") to convert ugly code into something much more readable. The below code is my attempt to emulate the behaviour in Base SAS.

/**************************************************************************
*     Program: codeformatter.sas
*      Author: Tom Bellmer
*     Created: 10Oct2014 
*     Purpose: Make SAS program more readable by placing one statemnt per  
*              line, indent code below PROC and DATA steps and indenting DO
*              constructs
*       Usage: %codeformatter( infile = , outfile = c:\temp\beautify.sas )
**************************************************************************/
%macro codeformatter( inputfile =, outputfile = c:\temp\codeout.sas ) ;
  %if not %sysfunc( fileexist( &inputfile. ) ) %then %do ;
    %put %str(E)RROR: The input file &inputfile. does not exist. ;
    %return ;
  %end ;

  data _null_ ;
    length 
      semicolonlocation startposition indent i commentoff 5 
      sasstatement $8 
      word $32767 ;
    retain commentoff 1 ;

    infile "&inputfile."  lrecl = 32767 truncover end = eof ;
    file   "&outputfile." lrecl = 32767 ;

    do until( eof ) ;
      input line $32767. ;
      startposition = 1 ;

      if find( line, '/*' ) then commentoff = 0 ;

      do i = 1 to max( count( line, ';' ), 1 ) ;
        semicolonlocation = find( line, ';', startposition  ) + 1 ; 

        if semicolonlocation = 1 then word = line ;
        else word = substr( line, startposition, ( semicolonlocation 
          - startposition ) ) ;

        startposition = semicolonlocation ;
        sasstatement = upcase( compress( scan( word, 1 ), ';' ) ) ;

        if sasstatement in ( 'LIBNAME', 'GOPTIONS', 'DATA', 'PROC', 'QUIT'
             , 'RUN', '*', '/*', 'OPTIONS', 'ODS', 'TITLE', 'FOOTNOTE'
             , 'FILENAME', 'RSUBMIT')  then do ;
          if sasstatement in ( 'PROC', 'DATA' ) then put ;
          indent = 0 ;
        end ;
        else indent = max( 2, indent ) ;

        if commentoff and ( find( word, 'end ', 'i' ) 
          or find( word, 'end;', 'i' ) ) 
           then indent = indent - 2 ;
        put +indent word ;

        if commentoff and ( find( lowcase( word ), 'do ' ) 
          or find( lowcase( word ), 'do;' ) ) 
           then indent + 2 ;
      end ;

      if find( line, '*/' ) then commentoff  = 1 ;
 
    end ;
  run ;
%mend ;

/* EOF: codeformatter.sas  */

No comments:

Post a Comment