Resolver variáveis ​​de macro SAS


13

A linguagem de programação SAS é uma linguagem arcaica e desajeitada que remonta a 1966, ainda em uso hoje. O compilador original foi escrito em PL / I e, de fato, grande parte da sintaxe deriva de PL / I. SAS também tem um pré-processador linguagem macro que deriva do que de PL / I também. Neste desafio, você interpretará alguns elementos simples da linguagem de macro SAS.

Na linguagem de macro SAS, as variáveis ​​de macro são definidas usando a %letpalavra - chave e a impressão no log é concluída %put. As instruções terminam com ponto e vírgula. aqui estão alguns exemplos:

%let x = 5;
%let cool_beans =Cool beans;
%let what123=46.lel"{)-++;

Os nomes de variáveis ​​de macro não diferenciam maiúsculas de minúsculas e sempre correspondem à expressão regular /[a-z_][a-z0-9_]*/i. Para os propósitos deste desafio, diremos o seguinte:

  • As variáveis ​​de macro podem conter apenas valores que consistem inteiramente em caracteres ASCII imprimíveis , exceto , e;&%
  • Não haverá espaços à esquerda ou à direita nos valores
  • Os valores nunca terão mais de 255 caracteres
  • Os valores podem estar vazios
  • Parênteses e aspas nos valores podem ser incomparáveis
  • Pode haver qualquer quantidade de espaço antes e depois do =no%let instrução e esse espaço deve ser ignorado
  • Pode haver qualquer quantidade de espaço antes do terminal ;na %letinstrução e esse espaço deve ser igualmente ignorado

Quando uma variável de macro é chamada, dizemos que "resolve" ao seu valor. Variáveis ​​de macro são resolvidas anexando-as &. Há um final opcional. que indica o final do identificador. Por exemplo,

%put The value of x is &X..;

escreve The value of x is 5.no log. Observe que dois períodos são necessários porque um único período será consumido &X.e resolvido para 5. Observe também que, embora tenhamos definido xem letras minúsculas, &Xé o mesmo que &xporque os nomes de variáveis ​​de macro não diferenciam maiúsculas de minúsculas.

Aqui é onde fica complicado. &S múltiplos podem ser agrupados para resolver variáveis &es no mesmo nível de resolução de aninhamento ao mesmo tempo. Por exemplo,

%let i = 1;
%let coolbeans1 = broseph;
%let broseph = 5;

%put &&coolbeans&i;  /* Prints broseph */
%put &&&coolbeans&i; /* Prints 5 */

Os mais internos &resolvem primeiro e a resolução continua para fora. A correspondência do nome da variável é feita com avidez. Na segunda %putinstrução, o processador faz as seguintes etapas:

  1. &iresolve 1e a liderança mais interna &é consumida, dando-nos&&coolbeans1
  2. &coolbeans1resolve broseph, dando-nos&broseph
  3. &brosephresolve para 5.

Se houver .s à direita , apenas um .será consumido na resolução, mesmo se houver vários& s.

Tarefa

Dado entre 1 e 10 %letdeclarações separadas por novas linhas e uma única %putdeclaração, imprima ou retorne o resultado da%put declaração. A entrada pode ser aceita de qualquer maneira padrão.

Você pode assumir que a entrada sempre será válida e que as %letinstruções precedem a %putdeclaração. Variáveis ​​definidas não serão redefinidas posteriormente%let instruções .

Se realmente executado no SAS, não haveria problemas com variáveis ​​resolvidas para variáveis ​​que não existem e tudo estará sintaticamente correto, conforme descrito acima.

Exemplos

  1. Entrada:

    %let dude=stuff;
    %let stuff=bEaNs;
    %put &&dude..;
    

    Resultado:

    bEaNs.
    
  2. Entrada:

    %let __6 = 6__;
    %put __6&__6;
    

    Resultado:

    __66__
    
  3. Entrada:

    %let i=1;
    %let hOt1Dog = BUNS;
    %put &&HoT&i.Dog are FUNS&i!");
    

    Resultado:

    BUNS are FUNS1!")
    
  4. Entrada:

    %let x = {*':TT7d;
    %put SAS is weird.;
    

    Resultado:

    SAS is weird.
    
  5. Entrada:

    %let var1   =  Hm?;
    %let var11 = var1;
    %let UNUSED = ;
    %put &&var11.....;
    

    Resultado:

    Hm?....
    

    Observe que &&var11corresponde, var11pois a correspondência de nomes é gananciosa. Se houvesse um ., ou seja &&var1.1, var1seria correspondido e o 1 extra não faria parte de nenhum nome.

Isso é código de golfe, então a solução mais curta em bytes vence!


Como a saída do caso de teste 1 tem um período? Não deve &stuff.remover o período?
GamrCorps

@GamrCorps Devo especificar: Apenas um único período à direita é consumido na resolução.
Alex A.

@GamrCorps Editado para especificar e incluí-lo como um caso de teste.
23416 Alex A.

por isso &&&&&&&&&a......................seria ainda só remover um período?
GamrCorps

@GamrCorps Sim.
23416 Alex A.

Respostas:


1

Python 3 , 354 341 336 bytes

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

Experimente online!

editar: alguns encurtamentos fáceis

edit: ordem inversa por -len (...) em vez de [:: - 1] (5 bytes), graças a 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
                            '&'+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 .

Eu sugeriria tomar muito na página de dicas do Python . Otimizações triviais, como concatenação de instruções não compostas ( ;), redução de parênteses ( if(...)-> if ...) e operações de lista ( ,reverse=1-> [::-1]) podem facilmente salvar alguns bytes.
Jonathan Frech

Obrigado! Já li isso antes, mas já faz muito tempo e esqueci alguns truques.
mmuntag 20/11/19

Você é bem vindo. len(y[0]))[::-1]pode ser -len(y[0])).
Jonathan Frech
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.