Устранение мертвого кода


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).
Flodel

3
@flodel Нет, не нужно смотреть на значения
Caridorc

@flodel testcase включен
Caridorc

Вы должны добавить тестовый пример, в котором переменная используется в выражении, но не в качестве первого элемента выражения. Особенно важно это как последний член выражения.
Исаак

@isaacg без мертвого кода, переменная может быть где угодно, добавлен
тестовый пример

Ответы:


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

Я знаю. Я просто пошутил. Извини :).
Cyphase

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.


@ Черная дыра У меня есть это исправлено.
Вниз

@ edc65 в соответствии с примерами, хотя разделитель является новой строкой. Ввод также в строгом формате с пробелами и т. Д.
Downgoat

@ edc65 Ты уверен? Попробуйте обернуть функцию в круглые скобки и запустить ее следующим образом. Это работает для меня (Safari Nightly).
Вниз

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

Спасибо за добавление моего предложения в ваш ответ. -1 потому что он все еще прослушивается
edc65

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.