Resolve SAS macro variables
Python 3, 354 341 336 bytes



import re
S=re.sub
def f(x):
&#9;r=x.splitlines();C=r[-1].strip('%put ');D=0
&#9;while D!=C:
&#9;&#9;D=C
&#9;&#9;for a in sorted([l.strip('%let ').replace(" ","").split(';')[0].split('=')for l in r[:-1]],key=lambda y:-len(y[0])):
&#9;&#9;&#9;s=1
&#9;&#9;&#9;while s:C,s=re.subn('&amp;'+a[0]+'(\.?)',a[1]+'\\1',S('+\.([^\.])','\\1',C),0,re.I)
&#9;return S('+\.?','',C)


Try it online!

edit: some easy shortening

edit: reverse sort by -len(...) instead of [::-1] (5 bytes), thanks to Jonathan Frech!

Ungolfed

import re
S=re.sub # new name for the function re.sub()
def f(x):
    r=x.splitlines() # input string to list of rows
    C=r[-1].strip('%put ') # get the string to put (from the last row)
    D=0
    while(D!=C): # iterate until the result does not change
        D=C
        for a in                                                                                                                    : # iterate over the list of variables
                 sorted(                                                                          ,key=lambda y:len(y[0]),reverse=1) # sort list for greediness by decreasing var.name lengths
                        [l.strip('%let ') # cut the 'let' keyword
                                         .replace(" ","") # erase spaces
                                                         .split(';')[0] # cut parts after ';'
                                                                       .split('=') # create [variable_name,value] list
                                                                                  for l in r[:-1]] # for each row but last
            s=1
            while(s): # iterate until the result does not change
                C,s=re.subn( # substitute
                            '&amp;'+a[0]+'(\.?)', # &varname. or &varname
                                                 a[1]+'\\1', # to value. or value
                                                              S('+\.([^\.])','\\1',C), # in the string we can get from C erasing ('s)(.) sequences if the next char is not .
                                                                                        0,re.I) # substituting is case insensitive
    return S('+\.?','',C) # erase smileys and one .