The SAS programming language is a clunky, archaic language dating back to 1966 that's still in use today. The original compiler was written in PL/I, and indeed much of the syntax derives from PL/I. SAS also has a preprocessor macro language which derives from that of PL/I as well. In this challenge, you'll be interpreting some simple elements of the SAS macro language.
In the SAS macro language, macro variables are defined using the %let
keyword and printing to the log is done with %put
. Statements end with semicolons. Here are some examples:
%let x = 5;
%let cool_beans =Cool beans;
%let what123=46.lel"{)-++;
Macro variable names are case insensitive and always match the regular expression /[a-z_][a-z0-9_]*/i
. For the purposes of this challenge, we'll say the following:
- Macro variables can only hold values consisting entirely of printable ASCII characters except
;
,&
, and%
- There will be no leading or trailing spaces in the values
- The values will never be more than 255 characters long
- Values may be empty
- Brackets and quotes in the values may be unmatched
- There can be any amount of space before and after the
=
in the%let
statement and this space should be ignored - There can be any amount of space before the terminal
;
in the%let
statement and this space should similarly be ignored
When a macro variable is called, we say it "resolves" to its value. Macro variables are resolved by prepending &
. There is an optional trailing .
that denotes the end of the identifier. For example,
%put The value of x is &X..;
writes The value of x is 5.
to the log. Note that two periods are required because a single period will be consumed by &X.
and resolve to 5
. Also note that even though we defined x
in lowercase, &X
is the same as &x
because macro variable names are case insensitive.
Here's where it gets tricky. Multiple &
s can be strung together to resolve variables, and &
s at the same level of nesting resolve at the same time. For example,
%let i = 1;
%let coolbeans1 = broseph;
%let broseph = 5;
%put &&coolbeans&i; /* Prints broseph */
%put &&&coolbeans&i; /* Prints 5 */
The innermost &
s resolve first, and resolution continues outward. Variable name matching is done greedily. In the second %put
statement, the processor makes the following steps:
&i
resolves to1
, and the innermost leading&
is consumed, giving us&&coolbeans1
&coolbeans1
resolves tobroseph
, giving us&broseph
&broseph
resolves to5
.
If there are trailing .
s, only a single .
is consumed in resolution, even if there are multiple &
s.
Task
Given between 1 and 10 %let
statements separated by newlines and a single %put
statement, print or return the result of the %put
statement. Input can be accepted in any standard way.
You can assume that the input will always be valid and that the %let
statements will preceed the %put
statement. Variables that are defined will not be redefined in later %let
statements.
If actually run in SAS, there would be no issues with variables resolving to variables that don't exist and everything will be syntactically correct as described above.
Examples
Input:
%let dude=stuff; %let stuff=bEaNs; %put &&dude..;
Output:
bEaNs.
Input:
%let __6 = 6__; %put __6&__6;
Output:
__66__
Input:
%let i=1; %let hOt1Dog = BUNS; %put &&HoT&i.Dog are FUNS&i!");
Output:
BUNS are FUNS1!")
Input:
%let x = {*':TT7d; %put SAS is weird.;
Output:
SAS is weird.
Input:
%let var1 = Hm?; %let var11 = var1; %let UNUSED = ; %put &&var11.....;
Output:
Hm?....
Note that
&&var11
matchesvar11
since name matching is greedy. If there had been a.
, i.e.&&var1.1
, thenvar1
would be matched and the extra 1 wouldn't be part of any name.
This is code golf, so the shortest solution in bytes wins!
&stuff.
remove the period? \$\endgroup\$&&&&&&&&&a......................
would still only remove one period? \$\endgroup\$