Eliminacja martwego kodu

20

Martwy kod siedzi i nic nie robi, wpatrując się w nas, wiedząc, że nigdy nie zostanie wykonany ... ale dziś możemy się zemścić.

Specyfikacja

Dane wejściowe będą ciągiem wieloliniowym.

Każda linia może być przypisaniem lub wyrażeniem .

Zadanie

Przypisanie ma postać, w <name> = numberktórej nazwa jest ciągiem liter, znaków podkreślenia i cyfr, ale nie zaczyna się od cyfry.

Zmienne można przypisywać dowolną liczbę razy.

Wyrażenie

Wyrażenie ma formę <var_name OR number> <operation> <var_name OR number> ...

Wyrażenie może być dowolną kombinacją:

  • Zmienne już zdefiniowane
  • Podstawowe operatory arytmetyczne +-*/
  • Liczby (liczby całkowite)

Oczekiwany wynik

Powinieneś wypisać ciąg z nadmiarowymi przypisaniami , przydziały , które nigdy nie są używane przez następujące po nim wyrażenia , usunięte. Należy pamiętać, że przypisania można również uczynić redundantnymi, jeśli dodatkowe przypisanie do tej samej zmiennej zostanie wykonane przed wykonaniem wyrażenia używającego zmiennej.

Przypadki testowe

w

a = 10
a * 3

na zewnątrz

a = 10
a * 3

w

foo = 8
2 - 1
a = 18

na zewnątrz

2 - 1

w

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

na zewnątrz

b = 4
b / 6
b + 1

w

a = 1
a = 2
a + 1

na zewnątrz

a = 2
a + 1

w

FooBar1 = 0
Fuz__ = 8
Fuz__ / 1

na zewnątrz

Fuz__ = 8
Fuz__ / 1

w

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

na zewnątrz

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

w

a = 1
1 / 5 * 8 + 4

na zewnątrz

1 / 5 * 8 + 4

w

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

na zewnątrz

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

w

a = 7
5 / a

na zewnątrz

a = 7
5 / a
Caridorc
źródło
1
Czy należy dodać ten szczególnie trudny przypadek a = 1; a + 1; a = 1; a + 1;:? Gdzie drugi a = 1można odrzucić tylko dlatego, że awcześniej był ustawiony na tę samą wartość ( 1).
flodel
3
@flodel Nie, nie trzeba patrzeć na wartości
Caridorc
Wbudowana walizka testowa @flodel
Caridorc
Należy dodać przypadek testowy, w którym zmienna jest używana w wyrażeniu, ale nie jako pierwszy element wyrażenia. Szczególnie ważny jest ostatni członek wyrażenia.
isaacg
@isaacg no dead code, var może być wszędzie, dodano testcase
Caridorc

Odpowiedzi:

9

PHP - 197 bajtów

Funkcja działa poprzez analizowanie każdej linii, w odwrotnej kolejności i jeden po drugim, oraz utrzymywanie tablicy używanych zmiennych.

  • Jeśli =w linii jest równy znak , jest to zadanie.
    • Jeśli zmienna jest używana, przypisanie jest przydatne, a linia jest drukowana, ale zmienna nie jest już uważana za użytą.
    • W przeciwnym razie nie rób nic.
  • W przeciwnym razie linia jest wyrażeniem. Dzielimy wiersz po każdej spacji i dodajemy każdy symbol do listy używanych zmiennych. Liczby ( 1, 2...) i operatorzy ( +, -...) zostaną dodane też, ale ponieważ nie są prawidłowymi nazwami zmiennych, to nie jest problem. Linia jest wtedy oczywiście drukowana.
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;}

Oto wersja bez golfa:

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;
}
Czarna dziura
źródło
7

Siatkówka , 45 bajtów

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

Dla celów zliczania, każda linia przechodzi w osobny plik (gdzie <empty>jest pusty plik) i \npowinna zostać zastąpiona rzeczywistym przesunięciem linii (0x0A).

Zakłada się, że ciąg zawsze kończy się wierszem.

Ponieważ regex nie korzysta z żadnych funkcji specyficznych dla platformy .NET, możesz go przetestować na regex101 .

Pomysł jest dość prosty: usuń wszystkie przypisania, z których możemy znaleźć (wyszukiwanie do przodu) innego przypisania do tej samej zmiennej lub końca łańcucha bez dalszego użycia tej zmiennej.

Martin Ender
źródło
6

Pyth, 40 bajtów

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

Wydaje się dość długi. Może jutro mogę zaoszczędzić jeden lub dwa bajty.

Wypróbuj online: pakiet demonstracyjny lub testowy

Wyjaśnienie:

_.__.zpodaje wszystkie postfiksy linii wejściowych w odwrotnej kolejności. Np. Dane wejściowe FooBar1 = 0; Fuz__ = 8; Fuz__ / 1dają listę:

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

Następnie filtruję elementy listy T, w których =nie ma ostatniego elementu T(wyrażenie) lub (przypisanie), ostatni element T, który zawiera nazwę zmiennej, jest wyrażeniem. Następnie wydrukuj ostatni element każdego z pozostałych elementów w osobnej linii.

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
Jakube
źródło
8
Aww to takie słodkie ....__.
lub
Ten kod kończy się niepowodzeniem na pyth.herokuapp.com/…
isaacg
@isaacg Naprawiono.
Jakube,
4

CJam, 49 bajtów

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

Wypróbuj online

Podejście polega na tym, że lista nieprzypisanych zmiennych jest utrzymywana podczas przetwarzania linii wejściowych z powrotem do przodu:

  • Jeśli wiersz jest wyrażeniem, wszystkie zmienne w wyrażeniu są dodawane do listy. W rzeczywistości w implementacji wszystkie tokeny są dodawane do listy, ponieważ zapisuje kod, a umieszczenie liczb i operatorów na liście nie powoduje żadnej szkody.

  • Jeśli linia jest przypisaniem, sprawdza, czy przypisana nazwa zmiennej znajduje się na liście. Jeśli tak, przypisanie jest akceptowane, a nazwa zmiennej usuwana z listy. W przeciwnym razie przypisanie zostanie pominięte.

Objaśnienie:

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.
Reto Koradi
źródło
4

Python 2, 270 267 bajtów

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])

Wcięcie to: 1. Spacja 2. Tab

Zaoszczędź 3 bajty dzięki @Kamehameha!

kirbyfan64sos
źródło
Przestrzeń po wydrukowaniu print ''.joini inna wydruku in [nmożna usunąć.
Kamehameha,
Możesz także użyć tej sztuczki, używając tabzamiast podwójnej spacji po exceptwierszu i zapisując jeden bajt.
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,"")

gdzie

  • L to linia od wejścia (zaczynająca się od ostatniej)
  • W to symbole (zmienne, operatory, liczby) w linii
  • Rto wektor symboli, które zostaną wydrukowane. Obejmuje zmienne, których przypisanie jest potrzebne.
  • Q jest wektorem linii na wyjściu
flodel
źródło
Można wymienić scan(what="",sep="\n")z scan(,"",sep="\n"). Być może będziesz w stanie zastąpić nazwany separgument jego ekwiwalentem pozycyjnym, ale nie pamiętam, dokąd poszłyby przecinki.
Alex A.
... oszczędzając 6. Bardzo miło. Dziękuję Alex!
flodel
2

JavaScript (ES6) 164 177

Za pomocą ciągów szablonów wszystkie znaki nowej linii są znaczące i zliczane.

Przetestuj uruchomienie fragmentu kodu w FireFox (wymagany do zgodności z ES6, w tym funkcji strzałek)

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>

edc65
źródło
Hej, to nie 164 bajty!
Cyphase,
@Cyphase linia 1:20 + 1 nowa linia, linia 2; 92 + 1 nowa linia, linia 3:48 + 1 nowa linia, linia 4: 1. 21 + 93 + 49 + 1 => 164. Ta ungolfedczęść służy wyłącznie do wyjaśnienia. Chodzi o TESTto ... emm tylko zgadnij ...
edc65
Wiem. Tylko żartowałem. Przepraszam :)
Cyphase
1

JavaScript ES6, 79 75 118 bajtów

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`
`

Powiedz mi, czy to nie działa w przypadku. Wszelkie pomysły na golfa są mile widziane.


Wyjaśnienie

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
  `

Testowane na Safari Nightly. Wersja przyjazna dla Firefoxa:

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`
`

Możesz wpaść do Babeljs, aby uzyskać wersję ES5.

Downgoat
źródło
@Blackhole Mam to naprawione.
Downgoat,
@ edc65 według przykładów separator jest jednak znakiem nowej linii. Dane wejściowe są również w ścisłym formacie ze spacjami itp.
Downgoat
@ edc65 Czy na pewno? Spróbuj owinąć funkcję w nawias i uruchom ją w ten sposób. Działa dla mnie (Safari Nightly).
Downgoat
Może jestem zbyt uparty, ale nadal uważam, że w każdym przypadku jest to zbyt proste. Sprawiłem, że działał bezbłędnie w Firefoksie, dodając nawiasy kwadratowe w wywołaniu wyszukiwania (wciąż znacznie krótszy niż mój). Próbowałem „a = 1 \ na + a \ na = 2”. I to się nie udaje ...
edc65,
Dziękujemy za dodanie mojej sugestii do Twojej odpowiedzi. -1, ponieważ nadal jest
uszkodzony
1

Haskell, 187 bajtów

Zastosowanie 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
Leif Willerts
źródło