Beseitigung toter Codes

20

Toter Code sitzt da und tut nichts. Er starrt uns an und weiß, dass er niemals ausgeführt wird ... aber heute können wir uns rächen.

Spezifikation

Die Eingabe ist eine mehrzeilige Zeichenfolge.

Jede Zeile kann entweder eine Zuweisung oder ein Ausdruck sein .

Zuordnung

Eine Zuordnung hat die Form <name> = number dass der Name eine Folge von Buchstaben, Unterstrichen und Zahlen ist, aber nicht mit einer Zahl beginnt.

Variablen können beliebig oft zugewiesen werden.

Ausdruck

Ein Ausdruck ist von der Form <var_name OR number> <operation> <var_name OR number> ...

Ein Ausdruck kann eine beliebige Kombination sein aus:

  • Bereits definierte Variablen
  • Grundrechenarten +-*/
  • Zahlen (ganze Zahlen)

Erwartete Ausgabe

Die Ausgabe sollte die Zeichenfolge mit redundanten Zuweisungen , Zuweisungen , die nie durch eine der verwendete Ausdrücke folgenden es, entfernt. Beachten Sie, dass Zuweisungen auch überflüssig werden können, wenn eine zusätzliche Zuweisung zu derselben Variablen vorgenommen wird, bevor ein Ausdruck mit der Variablen ausgeführt wird.

Testfälle

im

a = 10
a * 3

aus

a = 10
a * 3

im

foo = 8
2 - 1
a = 18

aus

2 - 1

im

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

aus

b = 4
b / 6
b + 1

im

a = 1
a = 2
a + 1

aus

a = 2
a + 1

im

FooBar1 = 0
Fuz__ = 8
Fuz__ / 1

aus

Fuz__ = 8
Fuz__ / 1

im

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

aus

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

im

a = 1
1 / 5 * 8 + 4

aus

1 / 5 * 8 + 4

im

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

aus

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

im

a = 7
5 / a

aus

a = 7
5 / a
Caridorc
quelle
1
Sollten Sie diesen besonders schwierigen Fall hinzufügen a = 1; a + 1; a = 1; a + 1;:? Wobei der zweite a = 1nur verworfen werden kann, weil azuvor der gleiche Wert eingestellt war ( 1).
Flodel
3
@flodel Nein, keine Notwendigkeit, Werte zu betrachten
Caridorc
@ Flodel Testcase aufgenommen
Caridorc
Sie sollten einen Testfall hinzufügen, in dem eine Variable in einem Ausdruck verwendet wird, jedoch nicht als erstes Element des Ausdrucks. Besonders wichtig ist als letztes Mitglied der Ausdruck.
Isaac
@isaacg kein toter Code, der var kann überall sein, Testfall hinzugefügt
Caridorc

Antworten:

9

PHP - 197 Bytes

Die Funktion analysiert jede Zeile in umgekehrter Reihenfolge und nacheinander und verwaltet ein Array der verwendeten Variablen.

  • Befindet sich =in der Zeile ein Gleichheitszeichen , handelt es sich um eine Zuweisung.
    • Wenn die Variable verwendet wird, die Zuweisung nützlich ist und die Zeile gedruckt wird, wird die Variable nicht mehr als verwendet betrachtet.
    • Sonst nichts tun.
  • Ansonsten ist die Zeile ein Ausdruck. Wir teilen die Zeile nach jedem Leerzeichen und fügen jedes Symbol der Liste der verwendeten Variablen hinzu. Numbers ( 1, 2, ...) und Betreiber ( +, -, ...) wird auch hinzugefügt werden, aber da sie nicht gültige Variablennamen sind, ist es kein Problem. Die Zeile wird dann natürlich ausgedruckt.
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;}

Hier ist die ungolfed Version:

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;
}
Schwarzes Loch
quelle
7

Netzhaut , 45 Bytes

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

Zu Zählzwecken wird jede Zeile in eine separate Datei verschoben (wobei <empty>es sich um eine leere Datei handelt) und \ndurch einen tatsächlichen Zeilenvorschub (0x0A) ersetzt.

Dies setzt voraus, dass die Zeichenfolge immer mit einem Zeilenvorschub endet.

Da dieser Regex keine .NET-spezifischen Funktionen verwendet, können Sie ihn auf Regex101 testen .

Die Idee ist ziemlich einfach: Entfernen Sie alle Zuweisungen, von denen wir eine andere Zuweisung für dieselbe Variable oder das Ende der Zeichenfolge finden (vorwärts suchen), ohne eine andere Verwendung der Variablen zu übergeben.

Martin Ender
quelle
6

Pyth, 40 Bytes

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

Scheint ein bisschen lang. Vielleicht kann ich morgen ein oder zwei Bytes speichern.

Probieren Sie es online aus: Demo oder Test Suite

Erläuterung:

_.__.zgibt alle Postfixes der Eingabezeilen in umgekehrter Reihenfolge an. ZB die Eingabe FooBar1 = 0; Fuz__ = 8; Fuz__ / 1gibt die Liste:

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

Dann filtere ich nach Listenelementen T, bei denen =nicht im letzten Element von T(Ausdruck) oder (Zuweisung) das letzte Element, in Tdem der Variablenname enthalten ist, ein Ausdruck ist. Drucken Sie anschließend das letzte Element aller verbleibenden Elemente in einer separaten Zeile aus.

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
quelle
8
Oh, es ist so süß ....__.
Orlp
Dieser Code schlägt auf pyth.herokuapp.com/…
isaacg
@isaacg behoben.
Jakube
4

CJam, 49 Bytes

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

Probieren Sie es online aus

Der Ansatz hier ist, dass eine Liste nicht zugewiesener Variablen beibehalten wird, während die Eingabezeilen von hinten nach vorne verarbeitet werden:

  • Wenn die Zeile ein Ausdruck ist, werden alle Variablen im Ausdruck zur Liste hinzugefügt. Tatsächlich werden in der Implementierung alle Token zur Liste hinzugefügt, da Code gespart wird und Zahlen und Operatoren in der Liste keinen Schaden anrichten.

  • Wenn es sich bei der Zeile um eine Zuweisung handelt, wird geprüft, ob der zugewiesene Variablenname in der Liste enthalten ist. Ist dies der Fall, wird die Zuweisung akzeptiert und der Variablenname aus der Liste entfernt. Andernfalls wird die Zuordnung übersprungen.

Erklärung:

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
quelle
4

Python 2, 270 267 Bytes

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

Einzug ist: 1. Leerzeichen 2. Tab

3 Bytes gespart dank @Kamehameha!

kirbyfan64sos
quelle
Der Raum nach dem Drucken in print ''.joinund inin in [nkann entfernt werden.
Kamehameha
Sie können diesen Trick auch anwenden, indem Sie tabanstelle des doppelten Leerzeichens nach der exceptZeile ein verwenden und ein Byte speichern.
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,"")

woher

  • L ist eine Zeile von der Eingabe (beginnend von der letzten)
  • W sind die Symbole (Variablen, Operatoren, Zahlen) in einer Zeile
  • Rist ein Vektor von Symbolen, die gedruckt werden. Es enthält Variablen, deren Zuordnung erforderlich ist.
  • Q ist der Vektor der Zeilen in der Ausgabe
Flodel
quelle
Sie können ersetzen scan(what="",sep="\n")mit scan(,"",sep="\n"). Möglicherweise können Sie das genannte sepArgument auch durch das entsprechende Positionsäquivalent ersetzen, aber ich kann mich nicht erinnern, wohin das Komma führen würde.
Alex A.
... 6 sparen. Sehr schön. Vielen Dank, Alex!
Flodel
2

JavaScript (ES6) 164 177

Bei Verwendung von Vorlagenzeichenfolgen sind alle Zeilenumbrüche von Bedeutung und werden gezählt.

Testlauf des Snippets in FireFox (für die ES6-Kompatibilität einschließlich Pfeilfunktionen erforderlich)

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
quelle
Hey, das sind keine 164 Bytes!
Cyphase
@Cyphase Zeile 1:20 + 1 Newline, Zeile 2; 92 + 1 Newline, Zeile 3:48 + 1 Newline, Zeile 4: 1. 21 + 93 + 49 + 1 => 164. Der ungolfedTeil dient nur zur Erläuterung. Der TESTTeil ist ... ähm nur erraten ...
edc65
Ich kenne. Ich habe nur Spaß gemacht. Es tut uns leid :).
Cyphase
1

JavaScript ES6, 79 75 118 Bytes

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

Sagen Sie mir, wenn dies für einen Fall nicht funktioniert. Anregungen zum Golfen sind willkommen.


Erläuterung

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
  `

Auf Safari Nightly getestet. Firefox-freundliche Version:

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

Sie können in babeljs vorbeischauen , um eine ES5-Version zu erhalten.

Downgoat
quelle
@Blackhole Ich habe das behoben.
Downgoat
@ edc65 Laut Beispielen ist das Trennzeichen jedoch ein Zeilenumbruch. Die Eingabe erfolgt ebenfalls in einem strengen Format mit Leerzeichen usw.
Downgoat
@ edc65 Bist du sicher? Versuchen Sie, die Funktion in Klammern zu setzen und so auszuführen. Es funktioniert bei mir (Safari Nightly).
Downgoat
Vielleicht bin ich zu hartnäckig, aber ich finde es immer noch zu einfach, in jedem Fall gut zu arbeiten. Ich habe es in Firefox fehlerfrei laufen lassen und Klammern in den Suchaufruf eingefügt (immer noch viel kürzer als meiner). Und versuchte "a = 1 \ na + a \ na = 2". Und es scheitert ...
edc65
Vielen Dank, dass Sie meinen Vorschlag zu Ihrer Antwort hinzugefügt haben. -1 weil es immer noch
fehlerhaft ist
1

Haskell, 187 Bytes

Verwenden 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
quelle