Усунення мертвого коду


20

Мертвий код сидить там і нічого не робить, дивиться на нас, знаючи, що він ніколи не буде виконаний ... але сьогодні ми можемо помститися.

Специфікація

Вхід буде багаторядковим рядком.

Кожен рядок може бути або призначенням, або виразом .

Призначення

Призначення має форму, <name> = numberде ім'я - це послідовність букв, підкреслення та цифр, але не починається з числа.

Змінні можуть бути призначені будь-яку кількість разів.

Вираз

Вираз має форму <var_name OR number> <operation> <var_name OR number> ...

Вираз може бути будь-якою комбінацією:

  • Змінні вже визначені
  • Основні арифметичні оператори +-*/
  • Числа (цілі числа)

Очікуваний вихід

Вивести рядок з резервуванням завдань , завдань , які ніколи не використовуються будь-яким з виразів після нього, вилучені. Зверніть увагу, що призначення також можуть бути надмірними, якщо додаткове присвоєння тій же змінній виконується до того, як буде виконано вираз із використанням змінної.

Тестові кейси

в

a = 10
a * 3

з

a = 10
a * 3

в

foo = 8
2 - 1
a = 18

з

2 - 1

в

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

з

b = 4
b / 6
b + 1

в

a = 1
a = 2
a + 1

з

a = 2
a + 1

в

FooBar1 = 0
Fuz__ = 8
Fuz__ / 1

з

Fuz__ = 8
Fuz__ / 1

в

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

з

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

в

a = 1
1 / 5 * 8 + 4

з

1 / 5 * 8 + 4

в

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

з

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

в

a = 7
5 / a

з

a = 7
5 / a

1
Чи варто додати цей особливо важкий випадок a = 1; a + 1; a = 1; a + 1;:? Де друге a = 1можна відкинути лише тому, що aраніше було встановлено таке ж значення ( 1).
флодель

3
@flodel Ні, не потрібно дивитися на значення
Caridorc

@flodel testcase включено
Caridorc

Вам слід додати тестовий випадок, коли змінна використовується в виразі, але не як перший елемент виразу. Особливо важливим є останній член виразу.
isaacg

@isaacg немає мертвого коду, вар може бути де завгодно, додано тест
Caridorc

Відповіді:


9

PHP - 197 байт

Функція працює, аналізуючи кожен рядок у зворотному порядку та один за одним та підтримуючи масив використаних змінних.

  • Якщо =в рядку є рівний символ , це призначення.
    • Це використовується змінна, призначення корисне, а рядок друкується, але ця зміна вже не вважається використаною.
    • Інакше нічого не робіть.
  • Інакше рядок - це вираз. Ділимо рядок після кожного пробілу і додаємо кожен символ до списку використаних змінних. Числа ( 1, 2, ...) і оператори ( +, -, ...) будуть додані теж, але так як вони не є іменами дійсного змінними, це не проблема. Потім, звичайно, друкується рядок.
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;}

Ось незворушена версія:

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

Сітківка , 45 байт

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

Для цілей підрахунку кожен рядок складається в окремому файлі (де <empty>порожній файл) і його \nслід замінити фактичним каналом рядка (0x0A).

Це передбачає, що рядок завжди закінчуватиметься стрічкою рядків.

Оскільки цей регекс не використовує жодних .NET-функцій, ви можете протестувати його на regex101 .

Ідея досить проста: видаліть усі завдання, з яких ми можемо знайти (шукаючи вперед) ще одне завдання до тієї самої змінної або кінець рядка, не передаючи інше використання змінної.


6

Pyth, 40 байт

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

Здається, ніби довго. Можливо, завтра я можу зберегти один-два байти.

Спробуйте в Інтернеті: Демонстрація або Тестовий набір

Пояснення:

_.__.zдає всі постфікси вхідних рядків у зворотному порядку. Наприклад, вхід FooBar1 = 0; Fuz__ = 8; Fuz__ / 1дає список:

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

Потім я фільтрую елементи списку T, в яких =немає в останньому елементі T(вираз) або (призначенні) останній елемент в T, який містить ім'я змінної, - це вираз. Після цього надрукуйте останній елемент кожного з решти елементів на окремому рядку.

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
Aww, це так мило ....__.
orlp

Цей код не вдається на pyth.herokuapp.com/…
isaacg

@isaacg Виправлено.
Якубе

4

CJam, 49 байт

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

Спробуйте в Інтернеті

Підхід тут полягає в тому, що під час обробки вхідних рядків назад до фронту зберігається список непризначених змінних:

  • Якщо рядок є виразом, всі змінні в виразі додаються до списку. Насправді при реалізації всі маркери додаються до списку, оскільки це зберігає код, а наявність номерів та операторів у списку не приносить ніякої шкоди.

  • Якщо рядок є призначенням, він перевіряє, чи вказане ім'я змінної є у ​​списку. Якщо це так, призначення приймається, а ім’я змінної видаляється зі списку. В іншому випадку завдання пропускається.

Пояснення:

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 байт

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

Відступ: 1. Пробіл 2. Табл

Збережено 3 байти завдяки @Kamehameha!


Простір після друку в print ''.joinі inв in [nможна видалити.
Камехамега

Крім того, ви можете використовувати цей трюк, використовуючи tabзамість подвійного пробілу за exceptрядком і зберігаючи один байт.
Камехамега

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,"")

де

  • L - рядок із входу (починаючи з останнього)
  • W - символи (змінні, оператори, числа) у рядку
  • R- вектор символів, який буде надрукований. Він включає змінні, призначення яких потрібно.
  • Q - вектор рядків у висновку

Ви можете замінити scan(what="",sep="\n")на scan(,"",sep="\n"). Можливо, ви також зможете замінити названий sepаргумент його позиційним еквівалентом, але я не можу пригадати, куди для цього пішли коми.
Алекс А.

... заощадження 6. Дуже приємно. Дякую Алекс!
flodel

2

JavaScript (ES6) 164 177

Використовуючи рядки шаблону, всі нові рядки є значущими та рахуються.

Тест запуску фрагмента в FireFox (необхідний для сумісності ES6, включаючи функції стрілок)

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>


Гей, це не 164 байти!
Сифаза

@Cyphase лінія 1:20 + 1 новий рядок, рядок 2; 92 + 1 новий рядок, рядок 3:48 + 1 новий рядок, рядок 4: 1. 21 + 93 + 49 + 1 => 164. ungolfedЧастина лише для пояснення. TESTЧастина ... ммм просто думаю ...
edc65

Я знаю. Я просто жартував. Вибачте :).
Сифаза

1

JavaScript ES6, 79 75 118 байт

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

Скажіть, якщо це не працює для випадку. Будь-які ідеї для гольфу вітаються.


Пояснення

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
  `

Тестується на Safari Nightly. 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`
`

Ви можете зайти в babeljs, щоб отримати версію ES5.


@Blackhole У мене це виправлено.
Пуховина

@ edc65, згідно з прикладами, роздільник є новим рядком. Введення також у строгому форматі з пробілами тощо
Downgoat

@ edc65 Ви впевнені? Спробуйте загорнути функцію в дужки і запустити її так. Це працює для мене (Safari Nightly).
Пуховина

Можливо, я занадто впертий, але я все ще вважаю, що занадто просто працювати добре у кожному випадку. Я змусив його працювати без помилок у Firefox, додаючи дужки в пошуковий виклик (все ще набагато коротший, ніж мій). І спробував "a = 1 \ na + a \ na = 2". І це не вдається ...
edc65

Thx для додавання моєї пропозиції до вашої відповіді. -1 тому, що все ще
помиляється

1

Haskell, 187 байт

Використовуйте 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.