Eliminazione del codice morto


20

Il codice morto rimane lì senza fare nulla, fissandoci sapendo che non verrà mai eseguito ... ma oggi possiamo vendicarci.

specificazione

L'input sarà una stringa multilinea.

Ogni riga può essere un compito o un'espressione .

Incarico

Un compito ha la forma in <name> = numbercui nome è una sequenza di lettere, caratteri di sottolineatura e numeri, ma non inizia con un numero.

Le variabili possono essere assegnate un numero qualsiasi di volte.

Espressione

Un'espressione ha la forma <var_name OR number> <operation> <var_name OR number> ...

Un'espressione può essere una qualsiasi combinazione di:

  • Variabili già definite
  • Operatori aritmetici di base +-*/
  • Numeri (numeri interi)

Uscita prevista

Dovresti generare la stringa con assegnazioni ridondanti , assegnazioni che non vengono mai utilizzate da nessuna delle espressioni che la seguono, rimosse. Si noti che le assegnazioni possono anche essere ridondanti se viene eseguita un'assegnazione aggiuntiva alla stessa variabile prima che venga eseguita un'espressione che utilizza la variabile.

Casi test

nel

a = 10
a * 3

su

a = 10
a * 3

nel

foo = 8
2 - 1
a = 18

su

2 - 1

nel

a = 10
a = 8
b = 4
ab = 72  
b / 6
b + 1

su

b = 4
b / 6
b + 1

nel

a = 1
a = 2
a + 1

su

a = 2
a + 1

nel

FooBar1 = 0
Fuz__ = 8
Fuz__ / 1

su

Fuz__ = 8
Fuz__ / 1

nel

a = 1
a + 1
a = 2
a + 1

su

a = 1
a + 1
a = 2
a + 1

nel

a = 1
1 / 5 * 8 + 4

su

1 / 5 * 8 + 4

nel

a = 1
a + 1
a = 1
a + 1

su

a = 1
a + 1
a = 1
a + 1

nel

a = 7
5 / a

su

a = 7
5 / a

1
In caso di aggiungere questo caso particolarmente difficile: a = 1; a + 1; a = 1; a + 1;? Dove il secondo a = 1può essere scartato solo perché aprecedentemente impostato sullo stesso valore ( 1).
flodel,

3
@flodel No, non c'è bisogno di guardare i valori
Caridorc,

@flodel testcase incorporated
Caridorc,

È necessario aggiungere un caso di test in cui una variabile viene utilizzata in un'espressione, ma non come primo elemento dell'espressione. Particolarmente importante è come l'ultimo membro dell'espressione.
isaacg,

@isaacg nessun codice morto, il var potrebbe essere ovunque, testcase aggiunto
Caridorc

Risposte:


9

PHP - 197 byte

La funzione funziona analizzando ciascuna riga, in ordine inverso e uno dopo l'altro, e mantenendo un array delle variabili utilizzate.

  • Se c'è un carattere uguale =nella riga, è un compito.
    • Se viene utilizzata la variabile, l'assegnazione è utile e la riga viene stampata, ma la variabile non viene più utilizzata.
    • Altrimenti, non fare nulla.
  • Altrimenti, la linea è un'espressione. Dividiamo la linea dopo ogni spazio e aggiungiamo ogni simbolo all'elenco delle variabili usate. Numeri ( 1, 2, ...) e operatori ( +, -, ...) saranno aggiunti anche, ma dal momento che non sono nomi di variabili validi, non è un problema. La linea viene quindi ovviamente stampata.
function($c){$u=[];foreach(array_reverse(split('
',$c))as$l){if($p=strpos($l,'=')){if(!isset($u[$x=substr($l,0,$p-1)]))continue;
unset($u[$x]);}else$u+=array_flip(split(' ',$l));$f="
$l$f";}echo$f;}

Ecco la versione ungolfed:

function removeDeadCode($code)
{
    $usedVariables = [];
    $finalCode = '';

    foreach (array_reverse(explode("\n", $code)) as $line)
    {
        if ($equalPosition = strpos($line, '='))
        {
            $variable = substr($line, 0, $equalPosition - 1);
            if (isset($usedVariables[$variable]))
            {
                $finalCode = "\n" . $line . $finalCode;
                unset($usedVariables[$variable]);
            }
        }
        else
        {
            $usedVariables += array_flip(explode(' ', $line));
            $finalCode = "\n" . $line . $finalCode;
        }
    }

    echo $finalCode;
}

7

Retina , 45 byte

m`^(\w+) =.*\n(?=((?!\b\1\b)[^!])*(^\1 =|\Z))
<empty>

Ai fini del conteggio, ogni riga va in un file separato (dove si <empty>trova un file vuoto) e \ndeve essere sostituita con un avanzamento riga effettivo (0x0A).

Ciò presuppone che la stringa finisca sempre con un avanzamento riga.

Poiché questo regex non utilizza alcuna funzionalità specifica di .NET, è possibile testarlo su regex101 .

L'idea è abbastanza semplice: rimuovere tutti i compiti da cui possiamo trovare (cercando in avanti) un altro compito alla stessa variabile o alla fine della stringa senza passare un altro uso della variabile.


6

Pyth, 40 byte

eMf|!}K\=eT&Jf}+dhceTK++dYdPT!}KeJ_.__.z

Sembra un po 'lungo. Forse potrei salvare uno o due byte domani.

Provalo online: dimostrazione o suite di test

Spiegazione:

_.__.zfornisce tutti i postfix delle righe di input in ordine inverso. Ad esempio, l'ingresso FooBar1 = 0; Fuz__ = 8; Fuz__ / 1fornisce l'elenco:

[['Fuz__ / 1', 'Fuz__ = 8', 'FooBar1 = 0'], 
 ['Fuz__ / 1', 'Fuz__ = 8']
 ['Fuz__ / 1']]

Quindi filtro per gli elementi dell'elenco T, in cui =non si trova nell'ultimo elemento di T(espressione) o (assegnazione) l'ultimo elemento in T, che contiene il nome della variabile, è un'espressione. Successivamente stampa l'ultimo elemento di ciascuno degli elementi rimanenti su una riga separata.

eMf|!}K\=eT&Jf}+dhceTK++dYdPT!}KeJ_.__.z
                                      .z  all input lines
                                     _    reverse order
                                   ._     all prefixes
                                  _       reverse order
  f                                       filter for elements T, which satisfy:
      K\=                                   K = '='
    !}K  eT                                 '=' is not in T[-1]
   |                                        or
             f             PT                 filter for elements Y in T[:-1],
                                              which satisfy:
                 hceTK                          extract variable name of T[-1]
                                                with an additional space at the end
               +d                               and at the beginning
              }       ++dYd                     ^ in space+Y+space
            J                                 assign these list to J
           &                                  J not empty and
                             !KeJ             '=' is not in J[-1]
eM                                        take the last element of each and print

8
Oh, è così carino ....__.
Orlp

Questo codice fallisce su pyth.herokuapp.com/…
isaacg il

@isaacg Risolto.
Jakube,

4

CJam, 49 byte

LqN/W%{_'=#_){(<:V1$\e=_{\Va-\}&}{;S/+1}?},\;W%N*

Provalo online

L'approccio qui è che un elenco di variabili non assegnate viene mantenuto durante l'elaborazione delle righe di input in primo piano:

  • Se la linea è un'espressione, tutte le variabili nell'espressione vengono aggiunte all'elenco. In realtà, nell'implementazione, tutti i token vengono aggiunti all'elenco, poiché salva il codice e avere numeri e operatori nell'elenco non fa alcun danno.

  • Se la riga è un compito, verifica se il nome della variabile assegnato è nell'elenco. In tal caso, l'assegnazione viene accettata e il nome della variabile viene rimosso dall'elenco. Altrimenti, l'assegnazione viene ignorata.

Spiegazione :

L     Start with empty list.
qN/   Get input and split at newlines.
W%    Reverse to process lines back to front.
{     Start of filter block.
  _     Copy line.
  '=#   Find equal sign.
  _     Copy position of equal sign, will use original later to extract
        variable name from assignment.
  )     Increment to produce truthy/falsy value (-1 from find means not found).
  {     Start if-block that processes assignments.
    (<    Slice off everything but variable name.
    :V    Save in variable V for later re-use.
    1$\   Place copy of unassigned variable list and new variable name at
          top of stack.
    e=    Count occurrences. This tells us if variable name was in list.
    _     Copy the condition value because it will also be used as the
          overall filter result.
    {     Start of block that removes variable name from list.
      \V    Bring list to top, and push variable name.
      a-    Remove the variable name from list.
      \     Swap to get variable list to bottom of stack for next iteration,
            and filter result to top.
    }&    End of conditional block to remove variable name.
  }     End of if-block for assignment.
  {     Start of else-block for expression.
    ;     Pop result of find operation.
    S/    Split expression at spaces.
    +     Concatenate the new variables with the existing ones in the list.
    1     Filter result, expressions are always accepted.
  }?    End of if for assignment vs. expression.
},    End of filter.
\;    Get rid of variable list at bottom of stack.
W%    Reverse order of filtered result, since we worked back to front.
N*    Join with newlines.

4

Python 2, 270 267 byte

import sys,re
d={}
s=list(enumerate(sys.stdin))
for n,l in s:
 try:v,_=l.split('=');v=v.strip();d[v]=d.get(v,[])+[[0,n]]
 except:
  for v in re.findall('[a-zA-Z_]\w*',l):d[v][-1][0]+=1
print''.join(l for n,l in s if n not in[n for x in d.values()for c,n in x if c==0])

Il rientro è: 1. Spazio 2. Scheda

3 byte salvati grazie a @Kamehameha!


Lo spazio dopo la stampa in print ''.joine inin in [npuò essere rimosso.
Kamehameha,

Inoltre, puoi usare questo trucco usando un tabinvece del doppio spazio dopo exceptriga e salvando un byte.
Kamehameha,

2

R 144

Q=R=c()
for(L in rev(scan(,"",,,"\n"))){W=strsplit(L," ")[[1]]
if("="%in%W)if(W[1]%in%R)R=R[R!=W[1]]else next else R=c(R,W)
Q=c(L,Q)}write(Q,"")

dove

  • L è una linea dall'input (a partire dall'ultima)
  • W sono i simboli (variabili, operatori, numeri) in una riga
  • Rè un vettore di simboli che verrà stampato. Include variabili di cui è necessaria l'assegnazione.
  • Q è il vettore di linee nell'output

È possibile sostituire scan(what="",sep="\n")con scan(,"",sep="\n"). Potresti anche essere in grado di sostituire l' separgomento nominato con il suo equivalente posizionale, ma non riesco a ricordare dove andrebbero le virgole.
Alex A.

... risparmio 6. Molto bello. Grazie Alex!
flodel,

2

JavaScript (ES6) 164 177

Utilizzando le stringhe modello, tutte le nuove righe sono significative e contate.

Test di esecuzione dello snippet in FireFox (richiesto per la compatibilità ES6, comprese le funzioni freccia)

f=s=>(k=>{s=s.split`
`,s.map((t,n)=>(r=t.match(/\w+/g)).map(v=>k[v]=f,~t.search`=`?k[s[k[v=r[0]]]=r[0]=0,v]=n:0))
for(v in k)s[k[v]]=0})([])||s.filter(r=>r).join`
`

ungolfed=s=>
{
  k={} // list line defining variables, by name, until used
  s=s.split`\n`
  s.forEach((t,n)=>
  {
    r=t.match(/\w+/g); // list variables in the line, operators are lost
    if (t.search`=` >= 0) // if it's an assignment
    {
      v=r[0] // new variable
      s[k[v]]=r[0]=0 // kill previous definition if not used
      k[v]=n
    }
    r.forEach(v=>k[v]='') // for each used variable, forget its definition line
  })
  for(v in k)s[k[v]]=0; // kill all remaining unused definitions
  return s.filter(r=>r).join`\n`
}

// TEST
out=x=>O.innerHTML+=x+'\n';


;[['a = 10\na * 3', 'a = 10\na * 3']
 ,['foo = 8\n2 - 1\na = 18','2 - 1'] 
 ,['a = 10\na = 8\nb = 4\nab = 72\nb / 6\nb + 1','b = 4\nb / 6\nb + 1'] 
 ,['a = 1\na = 2\na + 1','a = 2\na + 1'] 
 ,['FooBar1 = 0\nFuz__ = 8\nFuz__ / 1','Fuz__ = 8\nFuz__ / 1'] 
 ,['a = 1\na + 1\na = 2\na + 1','a = 1\na + 1\na = 2\na + 1']
 ,['a = 1\na + a\na = 2', 'a = 1\na + a']
 ,['a = 1\n1 / 5 * 8 + 4', '1 / 5 * 8 + 4']
 ,['a = 1\na + a\na = 2', 'a = 1\na + a']
 ,['a = 1\na + 1\na = 1\na + 1', 'a = 1\na + 1\na = 1\na + 1']
 ,['a = 7\n5 / a', 'a = 7\n5 / a']
]
.forEach(([i,k])=>(r=f(i),
  out('Test '+(r==k?'OK':'Fail')+'\nInput:  '+i.replace(/\n/g,',')
      +'\nResult: '+r.replace(/\n/g,',')
      +'\nCheck:  '+k.replace(/\n/g,',')+'\n')
));
Note: newlines trasformed to commas to save space in output
<pre id=O></pre>


Ehi, non sono 164 byte!
Cyphase

@Cifase riga 1:20 + 1 newline, linea 2; 92 + 1 newline, linea 3:48 + 1 newline, linea 4: 1. 21 + 93 + 49 + 1 => 164. La ungolfedparte ha solo scopo esplicativo. La TESTparte è ... uhm, indovina ...
edc65,

Lo so. Stavo solo scherzando. Scusa :).
Cyphase

1

JavaScript ES6, 79 75 118 byte

s=>s.split`
`.filter((l,i,a)=>(q=l.split`=`)[1]?!~(a.slice(i+1)+0).search(q[0]+'=')&&~s.search(q[0]+'[^=]'):1).join`
`

Dimmi se questo non funziona per un caso. Tutte le idee per il golf sono benvenute.


Spiegazione

s=>          // Function with argument "s"
  s.split`   // Splits each line
  `
  .filter(   // Filters through each line,
    (item,index,array)=>
      (q=l.split`=`)[1]? // If there is something after the equal sign
        !~ // XOR (~) will  essentially make -1, 0. NOT (!) will make 0, 1, vice-versa
         (a.slice(i+1)+0) // Gets following lines
         .search`^${z=q[0]}=` // Checks if following lines have the same variable name and then =
        && // AND...
         ~s.search(z+'[^=]') // Check if there is an expression with the variable
        :1) // If there is no equal sign, return 1 (true)
  .join` // Join everything back, seperated by newlines
  `

Testato su Safari Nightly. Versione per Firefox:

s=>s.split`
`.filter((l,i,a)=>(q=l.split`=`)[1]?!~(a.slice(i+1)+0).search(`^${z=q[0]}=`)&&~s.search(z+'[^=]'):1).join`
`

Puoi entrare in babeljs per ottenere una versione ES5.


@Blackhole L'ho risolto.
Downgoat,

@ edc65 secondo gli esempi il separatore è una nuova riga però. Anche l'input è in un formato rigoroso con spazi, ecc.
Downgoat,

@ edc65 Sei sicuro? Prova a racchiudere la funzione tra parentesi ed eseguila in questo modo. Funziona per me (Safari Nightly).
Downgoat,

Forse sono troppo ostinato ma sento ancora che è troppo semplice per funzionare bene in ogni caso. L'ho fatto funzionare senza errori in Firefox aggiungendo parentesi nella chiamata di ricerca (ancora molto più breve della mia). E ho provato "a = 1 \ na + a \ na = 2". E fallisce ...
edc65,

Grazie per aver aggiunto il mio suggerimento alla tua risposta. -1 perché è ancora
infastidito

1

Haskell, 187 byte

Usa d.

import Data.List
f=filter
(!)=map
b((v,e,w):t)=e||or((\(_,p,_)->p)!take 1(f(\(x,_,y)->v==x||v`elem`y)t))
d=unlines.(\l->snd!f fst(zip(b!tails(((\(v:o:w)->(v,o/="=",w)).words)!l))l)).lines
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.