Skip to content

Instantly share code, notes, and snippets.

@rkoopmann
Last active August 29, 2015 14:05
Show Gist options
  • Save rkoopmann/f59d7bc69cfc7b739eac to your computer and use it in GitHub Desktop.
Save rkoopmann/f59d7bc69cfc7b739eac to your computer and use it in GitHub Desktop.
parsing SAS macro scripts
/*********************************************************************************\
PROGRAM INFORMATION
Project : Autocall utilities
Purpose : Returns DATE in the specified format.
Inputs :
Outputs :
Notes :
PROGRAM HISTORY
2008-04-14 RK Initial program developed.
2009-11-06 RK To LEFT align output, need to QUOTE first then UNQUOTE.
2015-02-03 RK Updated the
\*********************************************************************************/;
%macro d(
format
, d=%sysfunc(left(%qsysfunc(date(),date9.)))
, interval=day
, increment=0
, alignment=b
);
%local macro; %let macro=&SYSMACRONAME;
%if &FORMAT eq %then %let format = date9;
%else %if %upcase(&FORMAT) eq HELP %then %do;
%put ***********************************************************************************;
%put * D Returns a date value in the specified format. *;
%put ***********************************************************************************;
%put * Positional Parameters (in this order): *;
%put * FORMAT The format to return DATE in. Defaults to date9. *;
%put * *;
%put * Optional Keyword Parameters (in any order): *;
%put * D Date value to use entered in date9. format. Default: current date. *;
%put * This can be assigned with an additional, nested #d macro call. *;
%put * INTERVAL Interval to shift the DATE parameter by. Defaults to day. *;
%put * INCREMENT Amount to shift the DATE parameter by. Defaults to 0. *;
%put * ALIGNMENT Sets the position of the result. Defaults to b(eginning). *;
%put ***********************************************************************************;
%put * Example macro call (replace # with percent symbol) *;
%put * #d(worddate, d=07DEC1942, interval=month, increment=5, alignment=s) *;
%put * #d(increment=3, d=#d(d=19NOV1863, interval=year.7, increment=-87)) *;
%put ***********************************************************************************;
dm log 'show';
%goto ByeBye;
%end;
%else %if %upcase(&FORMAT) eq EDIT %then %do;
%EditMacro(&MACRO);
%goto ByeBye;
%end;
%unquote(%left(%quote(%sysfunc(intnx(&INTERVAL, "&D"d, &INCREMENT, &ALIGNMENT), &FORMAT..))))
%ByeBye:
%mend d;

d.sas

d

Parameters:

  • format
  • d=&SYSDATE9
  • interval=day
  • increment=0
  • alignment=b

var_label.sas

var_label

Parameters:

  • data
  • var)/des='Returns the label of a given variable.'
#/usr/lib/perl
use strict;
use warnings;
use English;
use File::Basename;
use Time::localtime;
use File::stat;
# source directory
my $dir = '~/Documents/SAS/My\ Macros';
# target file
open (my $fo, '>', 'macro-index.md');
# source file
#printf $fo "# `%s`\n\n", $dir;
foreach my $fp (glob("$dir/*.sas")) {
# source line
printf $fo "\n## %s\n\n", basename $fp;
open my $fh, "<", $fp or die "can't read open '$fp': $OS_ERROR";
# printf $fo "%.2fkb, ", stat($fh)->size / 1024;
# printf $fo "created on %s", ctime(stat($fh)->ctime);
# printf $fo "last modified on %s\n\n", ctime(stat($fh)->mtime);
my $string="";
while (<$fh>) {
# trim each line and concatenate
$string .= trim($_);
}
close $fh or die "can't read close '$fp': $OS_ERROR";
# TODO: Currently, RE has problems parsing:
# - `%str()` -- the ending paren borks it
# - `/` -- anything after an option slash
# - `/* commas in comments, like that */` -- the comma borks it
# find any `%macro … ;` statement and parse it
if ($string=~/
%macro # start of macro statement
\s+ # one or more whitespace
(\w+) # CAPTURE name of macro being defined
\s* # possible whitespace
\(?(.*?)\)? # CAPTURE parameters
\s* # possible whitespace
# \/? # possible options indicator
# .*?
; # ending with the semi-colon
/ixg # ignore case, allow whitespace in re, global matching
) {
print $fo "\n### $1\n\nParameters:\n\n";
# parse parameter list, if present
if ("$2") {
# each parameter get a spot
my @params=split(',', $2);
foreach my $val (@params) {
printf $fo "- %s\n", trim($val);
}
}
else {
print $fo "- *NONE FOUND*\n";
}
}
else {
# print $string;
}
}
close $fo;
sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };
/*********************************************************************************\
PROGRAM INFORMATION
Project : Autocall utilities
Purpose : Returns the label of a given variable (based on AMACR A-12).
Inputs :
Outputs :
Notes :%vlabel(data,var)
data Data source name
var Variable of interest
PROGRAM HISTORY
07JUL2005 RK Initial program develped
\*********************************************************************************/;
%macro var_label(data,var)
/des='Returns the label of a given variable.';
%local dsid var_label;
%let dsid=%sysfunc(open(&data));
%let var_label=%qsysfunc(varlabel(&data,%sysfunc(varnum(&dsid,&var))));
%let dsid=%sysfunc(close(&dsid));
&var_label
%mend var_label;
@rkoopmann
Copy link
Author

Working on getting macro-index.pl to process all SAS files in specified directory and parse out:

  • macro name
    • word segment after %macro
  • parameter section
    • parameters are separated by commas
    • parameter values may contain parens and commas such as %str(a,b,c)
  • macro options
    • everything between / and ;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment